<?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=Davosmith</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=Davosmith"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Davosmith"/>
	<updated>2026-07-20T00:14:14Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=42400</id>
		<title>Course module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=42400"/>
		<updated>2013-09-26T14:21:13Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Database tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Summary==&lt;br /&gt;
A course module (often abbreviated &#039;cm&#039;) represents each of the activities and resources found in a course. It contains information about which course and section the activity / resource is displayed on, as well as details about the visibility, group and completion status of the activity.&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The data for the course module is stored in the database table &#039;mdl_course_modules&#039; (the &#039;mdl_&#039; part will be different if you have chosen a non-default prefix for your database tables). The fields in this table link it to a number of other tables in the database. &lt;br /&gt;
* The &#039;course&#039; field links to the &#039;mdl_course&#039; table, which contains everything you need to know about a course. &lt;br /&gt;
* The &#039;module&#039; table links to the &#039;mdl_modules&#039; table, which gives information about the type of the module (e.g. &#039;quiz&#039;, &#039;resource&#039;) as well as its current version number. &lt;br /&gt;
* After looking up the type of the module, the rest of the details about this module can be found by looking up the &#039;instance&#039; value (from the &#039;mdl_course_modules&#039; table) in the &#039;mdl_{type}&#039; table. Here you can find the name and introductory paragraph for the activity / resource, as well as information that is specific to the type of activity being looked at.&lt;br /&gt;
&lt;br /&gt;
You can quickly gather all of this information, by using the &#039;get_fast_modinfo($course)&#039; function. The easiest way to understand the data returned is to use the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $courseid));&lt;br /&gt;
$info = get_fast_modinfo($course);&lt;br /&gt;
print_object($info);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
The cmid (course module id) is used widely throughout Moodle to identify a specific activity / resource. Some of the most important uses are:&lt;br /&gt;
* When linking to a modules &#039;view.php&#039; script, it is passed as the &#039;id&#039; parameter&lt;br /&gt;
* To get the &#039;context&#039; for the module (used when checking user capabilities or linking files to an activity), via the function call &#039;context_module::instance($cmid)&#039; (before Moodle 2.2 this was &#039;get_context_instance(CONTEXT_MODULE, $cmid)&#039;)&lt;br /&gt;
* Every log entry in &#039;mdl_log&#039; that relates to a specific activity has the &#039;cmid&#039; field set&lt;br /&gt;
&lt;br /&gt;
==More documentation==&lt;br /&gt;
* [[Module visibility and display]]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/course_modinfo.html course_modinfo PHPdocs]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/cm_info.html cminfo PHPdocs]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File_API&amp;diff=41783</id>
		<title>File API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File_API&amp;diff=41783"/>
		<updated>2013-08-05T07:25:12Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Serving files to users */ Add an example of the MYPLUGIN_pluginfile function&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The File API is for managing all the files stored by Moodle. If you are interested in how the file API works internally, see [[File API internals]]. The page is just about what you need to know to use the file API. Related is the [[Repository API]], which lets users get files into Moodle.&lt;br /&gt;
&lt;br /&gt;
If you are looking for an explanation on how to manage moodle files in moodle forms, you most likely need to read [[Using_the_File_API_in_Moodle_forms|Using the File API in Moodle forms]].&lt;br /&gt;
&lt;br /&gt;
==File areas==&lt;br /&gt;
&lt;br /&gt;
Files are conceptually stored in &#039;&#039;&#039;file areas&#039;&#039;&#039;. A file area is uniquely identified by:&lt;br /&gt;
* A context id.&lt;br /&gt;
* full component name (using [[Frankenstyle]]), for example &#039;course&#039;, &#039;mod_forum&#039;, &#039;mod_glossary&#039;, &#039;block_html&#039;.&lt;br /&gt;
* A file area type, for example &#039;intro&#039; or &#039;post&#039;.&lt;br /&gt;
* A unique itemid. Normally, the itemid relates to something depending on the file area type. For example, for a &#039;course&#039;, &#039;intro&#039; file area, the itemid is 0. For forum post, it is the post id.&lt;br /&gt;
&lt;br /&gt;
File areas are not listed separately anywhere, they are stored implicitly in the files table. Please note that each subsystem is allowed to access only own file areas, for example only code in /mod/assignment/* may access files with component &#039;mod_assignment&#039;.&lt;br /&gt;
&lt;br /&gt;
===Naming file areas===&lt;br /&gt;
&lt;br /&gt;
The names of the file areas are not strictly defined, but it is strongly recommended to use singulars and common names of areas if possible (intro, post, attachment, description, ...).&lt;br /&gt;
&lt;br /&gt;
==Serving files to users==&lt;br /&gt;
&lt;br /&gt;
You must refer to the file with a URL that includes a file-serving script, often pluginfile.php. For example&lt;br /&gt;
&lt;br /&gt;
The general form of the URL is something like&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$url = $CFG-&amp;gt;wwwroot/pluginfile.php/$contextid/$component/$filearea/arbitrary/extra/infomation.ext&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A specific example might be&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$url = $CFG-&amp;gt;wwwroot/pluginfile.php/$forumcontextid/mod_forum/post/$postid/image.jpg&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually, you do not need to construct this URL directly - the function moodle_url::make_pluginfile_url() should be used instead:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$url = moodle_url::make_pluginfile_url($file-&amp;gt;get_contextid(), $file-&amp;gt;get_component(), $file-&amp;gt;get_filearea(), $file-&amp;gt;get_itemid(), $file-&amp;gt;get_filepath(), $file-&amp;gt;get_filename());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: If you do not need the &#039;itemid&#039;, then pass null in as this parameter and it will be entirely missed out from the URL - you need to take this into account when serving the file in the callback function, below.&lt;br /&gt;
&lt;br /&gt;
The file serving script then looks at the context id, and component name, and the file area name, and based on that arranges for the file to be served, following appropriate security checks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note: &amp;lt;/strong&amp;gt;In most cases, when developing third party plugins, pluginfile.php looks for a &#039;&#039;&#039;callback function&#039;&#039;&#039; in the appropriate plugin. These functions are stored in &#039;&#039;&#039;lib.php&#039;&#039;&#039; files and are named &#039;&#039;&#039;component_name_pluginfile()&#039;&#039;&#039;. The arbitrary/extra/infomation.ext is passed to the callback. For example, files in the mod_forum+post file area end up being served by the mod_forum_pluginfile function in mod/forum/lib.php. This function in MYPLUGIN/lib.php will usually follow a pattern like the example below, but the details will vary depending on the restrictions your plugin places on accessing different files (e.g. assignment files can only be accessed by teachers and the student who submitted the file, forum attachments require access to the discussion they are posted on):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function MYPLUGIN_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {&lt;br /&gt;
    // Check the contextlevel is as expected - if your plugin is a block, this becomes CONTEXT_BLOCK, etc.&lt;br /&gt;
    if ($context-&amp;gt;contextlevel != CONTEXT_MODULE) {&lt;br /&gt;
        return false; &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Make sure the filearea is one of those used by the plugin.&lt;br /&gt;
    if ($filearea !== &#039;expectedfilearea&#039; &amp;amp;&amp;amp; $filearea !== &#039;anotherexpectedfilearea&#039;) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Make sure the user is logged in and has access to the module (plugins that are not course modules should leave out the &#039;cm&#039; part).&lt;br /&gt;
    require_login($course, true, $cm);&lt;br /&gt;
&lt;br /&gt;
    // Check the relevant capabilities - these may vary depending on the filearea being accessed.&lt;br /&gt;
    if (!has_capability(&#039;mod/MYPLUGIN:view&#039;, $context)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Leave this line out if you set the itemid to null in make_pluginfile_url (set $itemid to 0 instead).&lt;br /&gt;
    $itemid = array_shift($args); // The first item in the $args array.&lt;br /&gt;
    &lt;br /&gt;
    // Use the itemid to retrieve any relevant data records and perform any security checks to see if the&lt;br /&gt;
    // user really does have access to the file in question.&lt;br /&gt;
&lt;br /&gt;
    // Extract the filename / filepath from the $args array.&lt;br /&gt;
    $filename = array_pop($args); // The last item in the $args array.&lt;br /&gt;
    if (!$args) {&lt;br /&gt;
        $filepath = &#039;/&#039;; // $args is empty =&amp;gt; the path is &#039;/&#039;&lt;br /&gt;
    } else {&lt;br /&gt;
        $filepath = &#039;/&#039;.implode(&#039;/&#039;, $args).&#039;/&#039;; // $args contains elements of the filepath&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Retrieve the file from the Files API.&lt;br /&gt;
    $fs = get_file_storage();&lt;br /&gt;
    $file = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;mod_MYPLUGIN&#039;, $filearea, $itemid, $filepath, $filename);&lt;br /&gt;
    if (!$file) {&lt;br /&gt;
        return false; // The file does not exist.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // We can now send the file back to the browser - in this case with a cache lifetime of 1 day and no filtering.&lt;br /&gt;
    send_file($file, 86400, 0, $forcedownload, $options);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You normally use an API function to generate these URL automatically, most often the &amp;lt;tt&amp;gt;file_rewrite_pluginfile_urls&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
==Getting files from the user==&lt;br /&gt;
&lt;br /&gt;
* See [[Using_the_File_API_in_Moodle_forms|Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Please note that in reality developers outside of core will not deal with file api directly in majority of cases, instead use formslib elements which are doing all this automatically.&lt;br /&gt;
&lt;br /&gt;
===Browsing files===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$browser = get_file_browser();&lt;br /&gt;
$context = get_system_context();&lt;br /&gt;
&lt;br /&gt;
$filearea = null;&lt;br /&gt;
$itemid   = null;&lt;br /&gt;
$filename = null;&lt;br /&gt;
if ($fileinfo = $browser-&amp;gt;get_file_info($context, $component, $filearea, $itemid, &#039;/&#039;, $filename)) {&lt;br /&gt;
    // build a Breadcrumb trail&lt;br /&gt;
    $level = $fileinfo-&amp;gt;get_parent();&lt;br /&gt;
    while ($level) {&lt;br /&gt;
        $path[] = array(&#039;name&#039;=&amp;gt;$level-&amp;gt;get_visible_name());&lt;br /&gt;
        $level = $level-&amp;gt;get_parent();&lt;br /&gt;
    }&lt;br /&gt;
    $path = array_reverse($path);&lt;br /&gt;
    $children = $fileinfo-&amp;gt;get_children();&lt;br /&gt;
    foreach ($children as $child) {&lt;br /&gt;
        if ($child-&amp;gt;is_directory()) {&lt;br /&gt;
            echo $child-&amp;gt;get_visible_name();&lt;br /&gt;
            // display contextid, itemid, component, filepath and filename&lt;br /&gt;
            var_dump($child-&amp;gt;get_params());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Moving files around===&lt;br /&gt;
&lt;br /&gt;
For example, if you have just built a file at the path&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $from_zip_file = $CFG-&amp;gt;dataroot . &#039;/temp/backup/&#039; . $preferences-&amp;gt;backup_unique_code .&lt;br /&gt;
         &#039;/&#039; . $preferences-&amp;gt;backup_name;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
And you want to move it into the course_backup file area, do&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $context = get_context_instance(CONTEXT_COURSE, $preferences-&amp;gt;backup_course);&lt;br /&gt;
 $fs = get_file_storage();&lt;br /&gt;
 $file_record = array(&#039;contextid&#039;=&amp;gt;$context-&amp;gt;id, &#039;component&#039;=&amp;gt;&#039;course&#039;, &#039;filearea&#039;=&amp;gt;&#039;backup&#039;,&lt;br /&gt;
         &#039;itemid&#039;=&amp;gt;0, &#039;filepath&#039;=&amp;gt;&#039;/&#039;, &#039;filename&#039;=&amp;gt;$preferences-&amp;gt;backup_name,&lt;br /&gt;
         &#039;timecreated&#039;=&amp;gt;time(), &#039;timemodified&#039;=&amp;gt;time());&lt;br /&gt;
 $fs-&amp;gt;create_file_from_pathname($file_record, $from_zip_file);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== List area files ===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
$files = $fs-&amp;gt;get_area_files($contextid, &#039;mod_assignment&#039;, &#039;submission&#039;, $submission-&amp;gt;id);&lt;br /&gt;
foreach ($files as $f) {&lt;br /&gt;
    // $f is an instance of stored_file&lt;br /&gt;
    echo $f-&amp;gt;get_filename();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or as links...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$out = array();&lt;br /&gt;
        &lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
$files = $fs-&amp;gt;get_area_files($contextid, &#039;mod_assignment&#039;, &#039;submission&#039;, $submission-&amp;gt;id);&lt;br /&gt;
            &lt;br /&gt;
foreach ($files as $file) {&lt;br /&gt;
    $filename = $file-&amp;gt;get_filename();&lt;br /&gt;
    $url = moodle_url::make_file_url(&#039;/pluginfile.php&#039;, array($file-&amp;gt;get_contextid(), &#039;mod_assignment&#039;, &#039;submission&#039;,&lt;br /&gt;
            $file-&amp;gt;get_itemid(), $file-&amp;gt;get_filepath(), $filename));&lt;br /&gt;
    $out[] = html_writer::link($url, $filename);&lt;br /&gt;
}&lt;br /&gt;
$br = html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
return implode($br, $out);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create file ===&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how to create a file whose contents will be a text string. This is the equivalent of the PHP function &amp;lt;tt&amp;gt;file_put_contents&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
&lt;br /&gt;
// Prepare file record object&lt;br /&gt;
$fileinfo = array(&lt;br /&gt;
    &#039;contextid&#039; =&amp;gt; $context-&amp;gt;id, // ID of context&lt;br /&gt;
    &#039;component&#039; =&amp;gt; &#039;mod_mymodule&#039;,     // usually = table name&lt;br /&gt;
    &#039;filearea&#039; =&amp;gt; &#039;myarea&#039;,     // usually = table name&lt;br /&gt;
    &#039;itemid&#039; =&amp;gt; 0,               // usually = ID of row in table&lt;br /&gt;
    &#039;filepath&#039; =&amp;gt; &#039;/&#039;,           // any path beginning and ending in /&lt;br /&gt;
    &#039;filename&#039; =&amp;gt; &#039;myfile.txt&#039;); // any filename&lt;br /&gt;
&lt;br /&gt;
// Create file containing text &#039;hello world&#039;&lt;br /&gt;
$fs-&amp;gt;create_file_from_string($fileinfo, &#039;hello world&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to create a file in the Moodle file area based on a &#039;real&#039; file e.g. in a temporary folder, you can use &amp;lt;tt&amp;gt;create_file_from_pathname&amp;lt;/tt&amp;gt; instead. Similarly, you can create a file based on some other file already in Moodle&#039;s local files by using &amp;lt;tt&amp;gt;create_file_from_storedfile&amp;lt;/tt&amp;gt;. Browse through &amp;lt;tt&amp;gt;lib/filestorage/file_storage.php&amp;lt;/tt&amp;gt; for details. &lt;br /&gt;
&lt;br /&gt;
Unlike with ordinary files, this method will not automatically overwrite an existing file. If you wish to overwrite a file, you must first get the file and (if it exists) delete it, and only then create it again.&lt;br /&gt;
&lt;br /&gt;
=== Read file ===&lt;br /&gt;
&lt;br /&gt;
This is a way to read a file, equivalent to &amp;lt;tt&amp;gt;file_get_contents&amp;lt;/tt&amp;gt;. &#039;&#039;&#039;Please note your are allowed to do this ONLY from mod/mymodule/* code, it is not acceptable to do this anywhere else.&#039;&#039;&#039; Other code has to use file_browser interface instead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
&lt;br /&gt;
// Prepare file record object&lt;br /&gt;
$fileinfo = array(&lt;br /&gt;
    &#039;component&#039; =&amp;gt; &#039;mod_mymodule&#039;,     // usually = table name&lt;br /&gt;
    &#039;filearea&#039; =&amp;gt; &#039;myarea&#039;,     // usually = table name&lt;br /&gt;
    &#039;itemid&#039; =&amp;gt; 0,               // usually = ID of row in table&lt;br /&gt;
    &#039;contextid&#039; =&amp;gt; $context-&amp;gt;id, // ID of context&lt;br /&gt;
    &#039;filepath&#039; =&amp;gt; &#039;/&#039;,           // any path beginning and ending in /&lt;br /&gt;
    &#039;filename&#039; =&amp;gt; &#039;myfile.txt&#039;); // any filename&lt;br /&gt;
&lt;br /&gt;
// Get file&lt;br /&gt;
$file = $fs-&amp;gt;get_file($fileinfo[&#039;contextid&#039;], $fileinfo[&#039;component&#039;], $fileinfo[&#039;filearea&#039;],&lt;br /&gt;
                      $fileinfo[&#039;itemid&#039;], $fileinfo[&#039;filepath&#039;], $fileinfo[&#039;filename&#039;]);&lt;br /&gt;
&lt;br /&gt;
// Read contents&lt;br /&gt;
if ($file) {&lt;br /&gt;
    $contents = $file-&amp;gt;get_content();&lt;br /&gt;
} else {&lt;br /&gt;
    // file doesn&#039;t exist - do something&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to access the file directly on disk, this is not permitted. Instead, you need to make a copy of the file in a temporary area and use that. You can do this with &amp;lt;tt&amp;gt;$file-&amp;gt;copy_content_to($pathname)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Delete file ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
&lt;br /&gt;
// Prepare file record object&lt;br /&gt;
$fileinfo = array(&lt;br /&gt;
    &#039;component&#039; =&amp;gt; &#039;mod_mymodule&#039;,&lt;br /&gt;
    &#039;filearea&#039; =&amp;gt; &#039;myarea&#039;,     // usually = table name&lt;br /&gt;
    &#039;itemid&#039; =&amp;gt; 0,               // usually = ID of row in table&lt;br /&gt;
    &#039;contextid&#039; =&amp;gt; $context-&amp;gt;id, // ID of context&lt;br /&gt;
    &#039;filepath&#039; =&amp;gt; &#039;/&#039;,           // any path beginning and ending in /&lt;br /&gt;
    &#039;filename&#039; =&amp;gt; &#039;myfile.txt&#039;); // any filename&lt;br /&gt;
&lt;br /&gt;
// Get file&lt;br /&gt;
$file = $fs-&amp;gt;get_file($fileinfo[&#039;contextid&#039;], $fileinfo[&#039;component&#039;], $fileinfo[&#039;filearea&#039;], &lt;br /&gt;
        $fileinfo[&#039;itemid&#039;], $fileinfo[&#039;filepath&#039;], $fileinfo[&#039;filename&#039;]);&lt;br /&gt;
&lt;br /&gt;
// Delete it if it exists&lt;br /&gt;
if ($file) {&lt;br /&gt;
    $file-&amp;gt;delete();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[File API internals]] how the File API works internally.&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Setting_up_xhprof_on_Moodle&amp;diff=37855</id>
		<title>Setting up xhprof on Moodle</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Setting_up_xhprof_on_Moodle&amp;diff=37855"/>
		<updated>2013-02-18T09:37:32Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Installing xhprof */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following instructions are for setting up xhprof for Moodle under a Ubuntu/Debian environment. The process should be similar for other linux enviroments, but will need some tweaking if you wish to do this under windows. Please update this document if you find any major problems.&lt;br /&gt;
&lt;br /&gt;
==Installing xhprof==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
mkdir ~/src/&lt;br /&gt;
cd ~/src/&lt;br /&gt;
wget http://pecl.php.net/get/xhprof-0.9.2.tgz&lt;br /&gt;
tar xvf xhprof-0.9.2.tgz&lt;br /&gt;
cd xhprof-0.9.2/extension/&lt;br /&gt;
phpize&lt;br /&gt;
./configure&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The version downloaded via these instructions is not compatible with PHP 5.4 - instead you should download the latest version of the code from https://github.com/facebook/xhprof (before following the instructions from &#039;cd xhprof-0.9.2/extension/&#039; onwards).&lt;br /&gt;
&lt;br /&gt;
Add the following to the apache version of you php.ini file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code ini&amp;gt;&lt;br /&gt;
[xhprof]&lt;br /&gt;
extension=xhprof.so&lt;br /&gt;
xhprof.output_dir=&amp;quot;/var/tmp/xhprof&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
sudo service apache2 restart&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a file in your web root that makes a call to phpinfo(); and then view the result in your browser to make sure that xhprof is enabled in PHP. Checking the output of &#039;&#039;&#039;php -m&#039;&#039;&#039; would also work if you are sure that the command line version of PHP uses the same php.ini file as your web server.&lt;br /&gt;
&lt;br /&gt;
==Configuring Moodle to use xhprof==&lt;br /&gt;
[[Image:profilingOption.png|thumb|left|The profiling option is displayed when the php xhprof extension is installed]]&lt;br /&gt;
[[Image:profilingOutput.png|thumb|right|Tabular profiling output produced by xhprof]]&lt;br /&gt;
[[Image:callgraph.png|thumb|right|An example call graph showing slow parts of the profiled run]]&lt;br /&gt;
Once the xhprof php extension is correctly installed you will find a new &amp;quot;Profiling&amp;quot; option available under Settings &amp;gt; Site administration &amp;gt; Development&lt;br /&gt;
&lt;br /&gt;
When you load the profiling settings page you are confronted with several options. In order to get xhprof up and running with minimal fuss you mearly need to check the &amp;quot;Enable profiling&amp;quot; box and set a path that you wish to be profiled. You can simply set this to a wildcard using the asterisk symbol (&#039;&#039;&#039;*&#039;&#039;&#039;) while you are testing profiling. Afterwards you can come back and set this to a more restrictive setting once you know profiling is working. Note the paths need to be specified relative to your Moodle directory and not the web root.&lt;br /&gt;
&lt;br /&gt;
After you have enabled profiling you should load some pages within the &amp;quot;Profile these&amp;quot; filter that you set in the step above. Once you have done these go to Settings &amp;gt; Site administration &amp;gt; Development &amp;gt; Profiling runs and you should see a list of the pages you visited. Clicking on one of these and then clicking on the &amp;quot;View profiling details&amp;quot; will take you to a profiling table full of helpful stats for tracking down slow pages and functions. You can get an even more ineresting breakdown of this by then clicking on the &amp;quot;View Full Callgraph&amp;quot; link. This callgraph makes it easy to see where the slow parts of each particular run are and functions which individually may not take a long time to run but which are run thousands of times and thus resulting in a great deal of slowdown.&lt;br /&gt;
[[Image:profilingSettings.png|frame|center|Enabling profiling and setting it to run on all pages via a wildcard]]&lt;br /&gt;
[[Image:profilingRuns.png|frame|left|A profiling runs option can be seen after enabling profiling]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=version.php&amp;diff=37342</id>
		<title>version.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=version.php&amp;diff=37342"/>
		<updated>2013-01-23T13:48:27Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Fixed Moodle 2.2 version number&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This file is included in the main directory of plugin. It is compulsory for most plugin types. Even when not compulsory it is highly recommended. &lt;br /&gt;
&lt;br /&gt;
It contains a number of fields, which are used during the install / upgrade process to make sure the plugin is compatible with the current Moodle install, as well as spotting whether an upgrade is needed.&lt;br /&gt;
&lt;br /&gt;
The file is a standard PHP file, starting with an opening &#039;&amp;amp;lt;?php&#039; tag and defining the following variables:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note! For Activity modules replace $plugin-&amp;gt; with $module-&amp;gt; in the following example!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* $plugin-&amp;gt;version = 2011051000;&lt;br /&gt;
** Required - the version number of your plugin in the form YYYYMMDDxx, so this example is 10th May 2011 (with 00 indicating this is the first version for that day)&lt;br /&gt;
* $plugin-&amp;gt;requires = 2010112400;&lt;br /&gt;
** Optional - minimum version number of Moodle that this plugin requires (Moodle 1.9 = 2007101509; Moodle 2.0 = 2010112400; Moodle 2.1 = 2011070100; Moodle 2.2 = 2011120500; Moodle 2.3 = 2012062500). See [[Releases]] for a full list.&lt;br /&gt;
* $plugin-&amp;gt;cron = 0;&lt;br /&gt;
** Optional - time interval (in seconds) between calls to the plugin&#039;s &#039;cron&#039; function; set to 0 to disable the cron function calls.&lt;br /&gt;
** Cron support is not yet implemented for all plugins.&lt;br /&gt;
* $plugin-&amp;gt;component = &#039;plugintype_pluginname&#039;;&lt;br /&gt;
** Optional - &#039;&#039;frankenstyle&#039;&#039; plugin name, strongly recommended. It is used for installation and upgrade diagnostics.&lt;br /&gt;
* $plugin-&amp;gt;maturity = MATURITY_STABLE;&lt;br /&gt;
** Optional - how stable the plugin is: MATURITY_ALPHA, MATURITY_BETA, MATURITY_RC, MATURITY_STABLE (Moodle 2.0 and above)&lt;br /&gt;
* $plugin-&amp;gt;release = &#039;2.x (Build: 2011051000)&#039;;&lt;br /&gt;
** Optional - Human-readable version name&lt;br /&gt;
* $plugin-&amp;gt;dependencies = array(&#039;mod_forum&#039; =&amp;gt; ANY_VERSION, &#039;mod_data&#039;  =&amp;gt; 2010020300);  &lt;br /&gt;
** Optional - list of other plugins that are required for this plugin to work (Moodle 2.2 and above)&lt;br /&gt;
** In this example, the plugin requires any version of the forum activity and version &#039;20100020300&#039; (or above) of the database activity&lt;br /&gt;
&lt;br /&gt;
Here is a template to copy and paste:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TODO&lt;br /&gt;
 *&lt;br /&gt;
 * @package   TODO_FRANKENSTYLE&lt;br /&gt;
 * @copyright TODO&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
$plugin-&amp;gt;version   = TODO;&lt;br /&gt;
$plugin-&amp;gt;requires  = TODO; // See https://docs.moodle.org/dev/Moodle_Versions&lt;br /&gt;
$plugin-&amp;gt;cron      = 0;&lt;br /&gt;
$plugin-&amp;gt;component = &#039;TODO_FRANKENSTYLE&#039;;&lt;br /&gt;
$plugin-&amp;gt;maturity  = MATURITY_STABLE;&lt;br /&gt;
$plugin-&amp;gt;release   = &#039;TODO&#039;;&lt;br /&gt;
&lt;br /&gt;
$plugin-&amp;gt;dependencies = array(&lt;br /&gt;
    &#039;mod_forum&#039; =&amp;gt; ANY_VERSION,&lt;br /&gt;
    &#039;mod_data&#039;  =&amp;gt; TODO&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Moodle versions]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=37299</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=37299"/>
		<updated>2013-01-21T16:34:34Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form($mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form($mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository::static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;src&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}====get_file_source_info($source)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime()====&lt;br /&gt;
Return minimum number of seconds before checking for changes to the file (default implementation = 1 day)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_file_lifetime($ref) {&lt;br /&gt;
    return 60 * 60 * 24; // One day&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file(stored_file $storedfile)====&lt;br /&gt;
Called after the file has reached the &#039;lifetime&#039; specified above to see if it should now be synchronised (default implementation is to return true)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function sync_individual_file(stored_file $storedfile) {&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_reference_details($reference, $filestatus = 0)====&lt;br /&gt;
Returns human-readable information about where the original file is stored (to be displayed in the filepicker properties box). It is usually prefixed with repository name and semicolon (e.g. &#039;Myrepository: http://url.to.file&#039;). $reference is the &#039;source&#039; output by &#039;get_listing&#039;. $filestatus can be either 0 (OK - default) or 666 (source file missing).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_details($reference, $filestatus = 0) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    if (!$filestatus) {&lt;br /&gt;
        $ref = unserialize(base64_decode($reference));&lt;br /&gt;
        return $this-&amp;gt;get_name(). &#039;: &#039;. $ref-&amp;gt;filename;&lt;br /&gt;
    } else {&lt;br /&gt;
        return get_string(&#039;lostsource&#039;, &#039;repository&#039;, &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference($reference)====&lt;br /&gt;
Returns up-to-date information about the original file, only called when the &#039;lifetime&#039; is reached and &#039;sync_individual_file&#039; returns true.&lt;br /&gt;
* for image files - download the file and return either $ret-&amp;gt;filepath (full path on the server), $ret-&amp;gt;handle (open handle to the file) or $ret-&amp;gt;content (raw data from the file) to allow the file to be saved into the Moodle filesystem and the thumbnail to be updated&lt;br /&gt;
* for non-image files - avoid downloading the file (if possible) and just return $ret-&amp;gt;filesize to update that information&lt;br /&gt;
* for missing / inaccessible files - return null&lt;br /&gt;
Remember this function may be called quite a lot, as the filemanager often wants to know the filesize.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file_by_reference($reference) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
    // Extract the remote file identifier&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference-&amp;gt;reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Download the file details&lt;br /&gt;
    $return = null;&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039; =&amp;gt; $cookiepathname));&lt;br /&gt;
    if (file_extension_in_typegroup($ref-&amp;gt;filename, &#039;web_image&#039;)) {&lt;br /&gt;
        // The file is an image - download and return the file path&lt;br /&gt;
        $path = $this-&amp;gt;prepare_file(&#039;&#039;);&lt;br /&gt;
        $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCIMAGE_TIMEOUT));&lt;br /&gt;
        if ($result === true) {&lt;br /&gt;
            $return = (object)array(&#039;filepath&#039; =&amp;gt; $path);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        // The file is not an image - just get the file details&lt;br /&gt;
        $result = $c-&amp;gt;head($url, array(&#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCFILE_TIMEOUT));&lt;br /&gt;
    }&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;connection_result($c-&amp;gt;get_errno());&lt;br /&gt;
    $curlinfo = $c-&amp;gt;get_info();&lt;br /&gt;
    if ($return === null &amp;amp;&amp;amp; isset($curlinfo[&#039;http_code&#039;]) &amp;amp;&amp;amp; $curlinfo[&#039;http_code&#039;] == 200&lt;br /&gt;
            &amp;amp;&amp;amp; array_key_exists(&#039;download_content_length&#039;, $curlinfo)&lt;br /&gt;
            &amp;amp;&amp;amp; $curlinfo[&#039;download_content_length&#039;] &amp;gt;= 0) {&lt;br /&gt;
        // we received a correct header and at least can tell the file size&lt;br /&gt;
        $return = (object)array(&#039;filesize&#039; =&amp;gt; $curlinfo[&#039;download_content_length&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
    return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====send_file($storedfile, $lifetime=86400, $filter=0, $forcedownload=false, array $options = null)====&lt;br /&gt;
Send the requested file back to the user&#039;s browser. The &#039;reference&#039; for the file can be found via $storedfile-&amp;gt;get_reference(). If the file is not found / no longer exists, the function &#039;send_file_not_found()&#039; should be used. Otherwise the file should be output directly, via the most appropriate method - e.g. use a &#039;Location: &#039; header to redirect to the external URL; or download the file and cache within the Moodle filesystem (possibly using &#039;$this-&amp;gt;import_external_file_contents()&#039;), then call &#039;send_stored_file&#039;. Note, it is up to the repository developer to decide whether to actually download the file or to return a locally cached copy instead.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function send_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    $reference  = unserialize(base64_decode($stored_file-&amp;gt;get_reference()));&lt;br /&gt;
    $url = $this-&amp;gt;appendtoken($reference-&amp;gt;url);&lt;br /&gt;
    if ($url) {&lt;br /&gt;
        header(&#039;Location: &#039; . $url);&lt;br /&gt;
    } else {&lt;br /&gt;
        send_file_not_found();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
An example of caching files within the Moodle filesystem can be found in repository_dropbox.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36814</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36814"/>
		<updated>2012-12-06T18:31:54Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Template */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}====get_file_source_info($source)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime()====&lt;br /&gt;
Return minimum number of seconds before checking for changes to the file (default implementation = 1 day)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_file_lifetime($ref) {&lt;br /&gt;
    return 60 * 60 * 24; // One day&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file(stored_file $storedfile)====&lt;br /&gt;
Called after the file has reached the &#039;lifetime&#039; specified above to see if it should now be synchronised (default implementation is to return true)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function sync_individual_file(stored_file $storedfile) {&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_reference_details($reference, $filestatus = 0)====&lt;br /&gt;
Returns human-readable information about where the original file is stored (to be displayed in the filepicker properties box). It is usually prefixed with repository name and semicolon (e.g. &#039;Myrepository: http://url.to.file&#039;). $reference is the &#039;source&#039; output by &#039;get_listing&#039;. $filestatus can be either 0 (OK - default) or 666 (source file missing).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_details($reference, $filestatus = 0) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    if (!$filestatus) {&lt;br /&gt;
        $ref = unserialize(base64_decode($reference));&lt;br /&gt;
        return $this-&amp;gt;get_name(). &#039;: &#039;. $ref-&amp;gt;filename;&lt;br /&gt;
    } else {&lt;br /&gt;
        return get_string(&#039;lostsource&#039;, &#039;repository&#039;, &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference($reference)====&lt;br /&gt;
Returns up-to-date information about the original file, only called when the &#039;lifetime&#039; is reached and &#039;sync_individual_file&#039; returns true.&lt;br /&gt;
* for image files - download the file and return either $ret-&amp;gt;filepath (full path on the server), $ret-&amp;gt;handle (open handle to the file) or $ret-&amp;gt;content (raw data from the file) to allow the file to be saved into the Moodle filesystem and the thumbnail to be updated&lt;br /&gt;
* for non-image files - avoid downloading the file (if possible) and just return $ret-&amp;gt;filesize to update that information&lt;br /&gt;
* for missing / inaccessible files - return null&lt;br /&gt;
Remember this function may be called quite a lot, as the filemanager often wants to know the filesize.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file_by_reference($reference) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
    // Extract the remote file identifier&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference-&amp;gt;reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Download the file details&lt;br /&gt;
    $return = null;&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039; =&amp;gt; $cookiepathname));&lt;br /&gt;
    if (file_extension_in_typegroup($ref-&amp;gt;filename, &#039;web_image&#039;)) {&lt;br /&gt;
        // The file is an image - download and return the file path&lt;br /&gt;
        $path = $this-&amp;gt;prepare_file(&#039;&#039;);&lt;br /&gt;
        $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCIMAGE_TIMEOUT));&lt;br /&gt;
        if ($result === true) {&lt;br /&gt;
            $return = (object)array(&#039;filepath&#039; =&amp;gt; $path);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        // The file is not an image - just get the file details&lt;br /&gt;
        $result = $c-&amp;gt;head($url, array(&#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCFILE_TIMEOUT));&lt;br /&gt;
    }&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;connection_result($c-&amp;gt;get_errno());&lt;br /&gt;
    $curlinfo = $c-&amp;gt;get_info();&lt;br /&gt;
    if ($return === null &amp;amp;&amp;amp; isset($curlinfo[&#039;http_code&#039;]) &amp;amp;&amp;amp; $curlinfo[&#039;http_code&#039;] == 200&lt;br /&gt;
            &amp;amp;&amp;amp; array_key_exists(&#039;download_content_length&#039;, $curlinfo)&lt;br /&gt;
            &amp;amp;&amp;amp; $curlinfo[&#039;download_content_length&#039;] &amp;gt;= 0) {&lt;br /&gt;
        // we received a correct header and at least can tell the file size&lt;br /&gt;
        $return = (object)array(&#039;filesize&#039; =&amp;gt; $curlinfo[&#039;download_content_length&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
    return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====send_file($storedfile, $lifetime=86400, $filter=0, $forcedownload=false, array $options = null)====&lt;br /&gt;
Send the requested file back to the user&#039;s browser. The &#039;reference&#039; for the file can be found via $storedfile-&amp;gt;get_reference(). If the file is not found / no longer exists, the function &#039;send_file_not_found()&#039; should be used. Otherwise the file should be output directly, via the most appropriate method - e.g. use a &#039;Location: &#039; header to redirect to the external URL; or download the file and cache within the Moodle filesystem (possibly using &#039;$this-&amp;gt;import_external_file_contents()&#039;), then call &#039;send_stored_file&#039;. Note, it is up to the repository developer to decide whether to actually download the file or to return a locally cached copy instead.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function send_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    $reference  = unserialize(base64_decode($stored_file-&amp;gt;get_reference()));&lt;br /&gt;
    $url = $this-&amp;gt;appendtoken($reference-&amp;gt;url);&lt;br /&gt;
    if ($url) {&lt;br /&gt;
        header(&#039;Location: &#039; . $url);&lt;br /&gt;
    } else {&lt;br /&gt;
        send_file_not_found();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
An example of caching files within the Moodle filesystem can be found in repository_dropbox.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36807</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36807"/>
		<updated>2012-12-05T20:57:30Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* instance_config_form($mform) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}====get_file_source_info($source)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime()====&lt;br /&gt;
Return minimum number of seconds before checking for changes to the file (default implementation = 1 day)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_file_lifetime($ref) {&lt;br /&gt;
    return 60 * 60 * 24; // One day&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file(stored_file $storedfile)====&lt;br /&gt;
Called after the file has reached the &#039;lifetime&#039; specified above to see if it should now be synchronised (default implementation is to return true)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function sync_individual_file(stored_file $storedfile) {&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_reference_details($reference, $filestatus = 0)====&lt;br /&gt;
Returns human-readable information about where the original file is stored (to be displayed in the filepicker properties box). It is usually prefixed with repository name and semicolon (e.g. &#039;Myrepository: http://url.to.file&#039;). $reference is the &#039;source&#039; output by &#039;get_listing&#039;. $filestatus can be either 0 (OK - default) or 666 (source file missing).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_details($reference, $filestatus = 0) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    if (!$filestatus) {&lt;br /&gt;
        $ref = unserialize(base64_decode($reference));&lt;br /&gt;
        return $this-&amp;gt;get_name(). &#039;: &#039;. $ref-&amp;gt;filename;&lt;br /&gt;
    } else {&lt;br /&gt;
        return get_string(&#039;lostsource&#039;, &#039;repository&#039;, &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference($reference)====&lt;br /&gt;
Returns up-to-date information about the original file, only called when the &#039;lifetime&#039; is reached and &#039;sync_individual_file&#039; returns true.&lt;br /&gt;
* for image files - download the file and return either $ret-&amp;gt;filepath (full path on the server), $ret-&amp;gt;handle (open handle to the file) or $ret-&amp;gt;content (raw data from the file) to allow the file to be saved into the Moodle filesystem and the thumbnail to be updated&lt;br /&gt;
* for non-image files - avoid downloading the file (if possible) and just return $ret-&amp;gt;filesize to update that information&lt;br /&gt;
* for missing / inaccessible files - return null&lt;br /&gt;
Remember this function may be called quite a lot, as the filemanager often wants to know the filesize.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file_by_reference($reference) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
    // Extract the remote file identifier&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference-&amp;gt;reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Download the file details&lt;br /&gt;
    $return = null;&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039; =&amp;gt; $cookiepathname));&lt;br /&gt;
    if (file_extension_in_typegroup($ref-&amp;gt;filename, &#039;web_image&#039;)) {&lt;br /&gt;
        // The file is an image - download and return the file path&lt;br /&gt;
        $path = $this-&amp;gt;prepare_file(&#039;&#039;);&lt;br /&gt;
        $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCIMAGE_TIMEOUT));&lt;br /&gt;
        if ($result === true) {&lt;br /&gt;
            $return = (object)array(&#039;filepath&#039; =&amp;gt; $path);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        // The file is not an image - just get the file details&lt;br /&gt;
        $result = $c-&amp;gt;head($url, array(&#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCFILE_TIMEOUT));&lt;br /&gt;
    }&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;connection_result($c-&amp;gt;get_errno());&lt;br /&gt;
    $curlinfo = $c-&amp;gt;get_info();&lt;br /&gt;
    if ($return === null &amp;amp;&amp;amp; isset($curlinfo[&#039;http_code&#039;]) &amp;amp;&amp;amp; $curlinfo[&#039;http_code&#039;] == 200&lt;br /&gt;
            &amp;amp;&amp;amp; array_key_exists(&#039;download_content_length&#039;, $curlinfo)&lt;br /&gt;
            &amp;amp;&amp;amp; $curlinfo[&#039;download_content_length&#039;] &amp;gt;= 0) {&lt;br /&gt;
        // we received a correct header and at least can tell the file size&lt;br /&gt;
        $return = (object)array(&#039;filesize&#039; =&amp;gt; $curlinfo[&#039;download_content_length&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
    return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====send_file($storedfile, $lifetime=86400, $filter=0, $forcedownload=false, array $options = null)====&lt;br /&gt;
Send the requested file back to the user&#039;s browser. The &#039;reference&#039; for the file can be found via $storedfile-&amp;gt;get_reference(). If the file is not found / no longer exists, the function &#039;send_file_not_found()&#039; should be used. Otherwise the file should be output directly, via the most appropriate method - e.g. use a &#039;Location: &#039; header to redirect to the external URL; or download the file and cache within the Moodle filesystem (possibly using &#039;$this-&amp;gt;import_external_file_contents()&#039;), then call &#039;send_stored_file&#039;. Note, it is up to the repository developer to decide whether to actually download the file or to return a locally cached copy instead.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function send_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    $reference  = unserialize(base64_decode($stored_file-&amp;gt;get_reference()));&lt;br /&gt;
    $url = $this-&amp;gt;appendtoken($reference-&amp;gt;url);&lt;br /&gt;
    if ($url) {&lt;br /&gt;
        header(&#039;Location: &#039; . $url);&lt;br /&gt;
    } else {&lt;br /&gt;
        send_file_not_found();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
An example of caching files within the Moodle filesystem can be found in repository_dropbox.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36806</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36806"/>
		<updated>2012-12-05T20:55:12Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Repository APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}====get_file_source_info($source)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime()====&lt;br /&gt;
Return minimum number of seconds before checking for changes to the file (default implementation = 1 day)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_file_lifetime($ref) {&lt;br /&gt;
    return 60 * 60 * 24; // One day&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file(stored_file $storedfile)====&lt;br /&gt;
Called after the file has reached the &#039;lifetime&#039; specified above to see if it should now be synchronised (default implementation is to return true)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function sync_individual_file(stored_file $storedfile) {&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_reference_details($reference, $filestatus = 0)====&lt;br /&gt;
Returns human-readable information about where the original file is stored (to be displayed in the filepicker properties box). It is usually prefixed with repository name and semicolon (e.g. &#039;Myrepository: http://url.to.file&#039;). $reference is the &#039;source&#039; output by &#039;get_listing&#039;. $filestatus can be either 0 (OK - default) or 666 (source file missing).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_reference_details($reference, $filestatus = 0) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    if (!$filestatus) {&lt;br /&gt;
        $ref = unserialize(base64_decode($reference));&lt;br /&gt;
        return $this-&amp;gt;get_name(). &#039;: &#039;. $ref-&amp;gt;filename;&lt;br /&gt;
    } else {&lt;br /&gt;
        return get_string(&#039;lostsource&#039;, &#039;repository&#039;, &#039;&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference($reference)====&lt;br /&gt;
Returns up-to-date information about the original file, only called when the &#039;lifetime&#039; is reached and &#039;sync_individual_file&#039; returns true.&lt;br /&gt;
* for image files - download the file and return either $ret-&amp;gt;filepath (full path on the server), $ret-&amp;gt;handle (open handle to the file) or $ret-&amp;gt;content (raw data from the file) to allow the file to be saved into the Moodle filesystem and the thumbnail to be updated&lt;br /&gt;
* for non-image files - avoid downloading the file (if possible) and just return $ret-&amp;gt;filesize to update that information&lt;br /&gt;
* for missing / inaccessible files - return null&lt;br /&gt;
Remember this function may be called quite a lot, as the filemanager often wants to know the filesize.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file_by_reference($reference) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
    // Extract the remote file identifier&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference-&amp;gt;reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Download the file details&lt;br /&gt;
    $return = null;&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039; =&amp;gt; $cookiepathname));&lt;br /&gt;
    if (file_extension_in_typegroup($ref-&amp;gt;filename, &#039;web_image&#039;)) {&lt;br /&gt;
        // The file is an image - download and return the file path&lt;br /&gt;
        $path = $this-&amp;gt;prepare_file(&#039;&#039;);&lt;br /&gt;
        $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCIMAGE_TIMEOUT));&lt;br /&gt;
        if ($result === true) {&lt;br /&gt;
            $return = (object)array(&#039;filepath&#039; =&amp;gt; $path);&lt;br /&gt;
        }&lt;br /&gt;
    } else {&lt;br /&gt;
        // The file is not an image - just get the file details&lt;br /&gt;
        $result = $c-&amp;gt;head($url, array(&#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::SYNCFILE_TIMEOUT));&lt;br /&gt;
    }&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;connection_result($c-&amp;gt;get_errno());&lt;br /&gt;
    $curlinfo = $c-&amp;gt;get_info();&lt;br /&gt;
    if ($return === null &amp;amp;&amp;amp; isset($curlinfo[&#039;http_code&#039;]) &amp;amp;&amp;amp; $curlinfo[&#039;http_code&#039;] == 200&lt;br /&gt;
            &amp;amp;&amp;amp; array_key_exists(&#039;download_content_length&#039;, $curlinfo)&lt;br /&gt;
            &amp;amp;&amp;amp; $curlinfo[&#039;download_content_length&#039;] &amp;gt;= 0) {&lt;br /&gt;
        // we received a correct header and at least can tell the file size&lt;br /&gt;
        $return = (object)array(&#039;filesize&#039; =&amp;gt; $curlinfo[&#039;download_content_length&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
    return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====send_file($storedfile, $lifetime=86400, $filter=0, $forcedownload=false, array $options = null)====&lt;br /&gt;
Send the requested file back to the user&#039;s browser. The &#039;reference&#039; for the file can be found via $storedfile-&amp;gt;get_reference(). If the file is not found / no longer exists, the function &#039;send_file_not_found()&#039; should be used. Otherwise the file should be output directly, via the most appropriate method - e.g. use a &#039;Location: &#039; header to redirect to the external URL; or download the file and cache within the Moodle filesystem (possibly using &#039;$this-&amp;gt;import_external_file_contents()&#039;), then call &#039;send_stored_file&#039;. Note, it is up to the repository developer to decide whether to actually download the file or to return a locally cached copy instead.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function send_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {&lt;br /&gt;
// Example taken from repository_equella&lt;br /&gt;
    $reference  = unserialize(base64_decode($stored_file-&amp;gt;get_reference()));&lt;br /&gt;
    $url = $this-&amp;gt;appendtoken($reference-&amp;gt;url);&lt;br /&gt;
    if ($url) {&lt;br /&gt;
        header(&#039;Location: &#039; . $url);&lt;br /&gt;
    } else {&lt;br /&gt;
        send_file_not_found();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
An example of caching files within the Moodle filesystem can be found in repository_dropbox.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36805</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36805"/>
		<updated>2012-12-05T20:44:24Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* get_file_source_info($source) (2.3+) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}====get_file_source_info($source)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36804</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36804"/>
		<updated>2012-12-05T20:43:58Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Repository support for returning file as alias/shortcut */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info($source) (2.3+)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.3}}===Repository support for returning file as alias/shortcut=== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36803</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36803"/>
		<updated>2012-12-05T20:41:59Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Repository APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info($source) (2.3+)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36802</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36802"/>
		<updated>2012-12-05T20:41:26Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Search functions (optional) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info($source) (2.3+)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
These functions allow you to implement search functionality within your repository.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
&lt;br /&gt;
    // label search name&lt;br /&gt;
    $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
    $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
    $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
    // text field search name&lt;br /&gt;
    $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
    $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
    $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
    $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
    $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
      &lt;br /&gt;
    return $html;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search($search_text, $page = 0)====&lt;br /&gt;
Return the results of doing the search. Any additional parameters from the search form can be retrieved by $param = optional_param(&#039;paramname&#039;, [defaultvalue], PARAM_INT / PARAM_TEXT);. The return should return an array containing:&lt;br /&gt;
* list - with the same layout as the &#039;list&#039; element in &#039;get_listing&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function search($search_text, $page = 0) { &lt;br /&gt;
// Example from repoistory_googledocs&lt;br /&gt;
    $gdocs = new google_docs($this-&amp;gt;googleoauth);&lt;br /&gt;
&lt;br /&gt;
    $ret = array();&lt;br /&gt;
    $ret[&#039;dynload&#039;] = true;&lt;br /&gt;
    $ret[&#039;list&#039;] = $gdocs-&amp;gt;get_file_list($search_text);&lt;br /&gt;
    return $ret;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====global_search()====&lt;br /&gt;
Return true if should be included in a search throughout all repositories (currently not available via the UI)&lt;br /&gt;
&lt;br /&gt;
===Misc functions===&lt;br /&gt;
&lt;br /&gt;
A couple of other useful functions to be aware of.&lt;br /&gt;
&lt;br /&gt;
====get_name()====&lt;br /&gt;
Returns the human-readable name for this instance of the plugin (the default implementation should usually be fine and this function can be useful when doing any output to the user).&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
For any background tasks that need to be scheduled (rarely needed). The minimum time between calls is specified in the version.php file (but the maximum time depends on the server settings for the Moodle install).&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36801</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36801"/>
		<updated>2012-12-05T20:36:33Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* print_search */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info($source) (2.3+)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
The following fields are automatically inserted in Moodle 2.3+ (but may need to be manually included in earlier versions):&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_search() {&lt;br /&gt;
    // The default implementation in class &#039;repository&#039;&lt;br /&gt;
    global $PAGE;&lt;br /&gt;
    $renderer = $PAGE-&amp;gt;get_renderer(&#039;core&#039;, &#039;files&#039;);&lt;br /&gt;
    return $renderer-&amp;gt;repository_default_searchform();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// From core_files_renderer (repository/renderer.php)&lt;br /&gt;
public function repository_default_searchform() {&lt;br /&gt;
    $str = &#039;&amp;lt;div class=&amp;quot;fp-def-search&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;s&amp;quot; value=&#039;.get_string(&#039;search&#039;, &#039;repository&#039;).&#039; /&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
    return $str;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36800</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36800"/>
		<updated>2012-12-05T20:32:55Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Transferring files to Moodle (optional) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_link($url)====&lt;br /&gt;
Used with FILE_EXTERNAL to convert a reference (from &#039;get_file_reference&#039;, but ultimately from the output of &#039;get_listing&#039;) into a URL that can be used directly by the end-user&#039;s browser. Usually just returns the original $url, but may need further transformation based on the internal implementation of the repository plugin.&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info($source) (2.3+)====&lt;br /&gt;
Takes the &#039;source&#039; field from &#039;get_listing&#039; (as returned by the user&#039;s browser) and returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
===Search functions (optional)===&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36788</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36788"/>
		<updated>2012-12-05T12:34:05Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* get_file($url, $filename = ) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &amp;quot;&amp;quot;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36787</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36787"/>
		<updated>2012-12-05T12:33:30Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Functions you can override */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===User login (optional)===&lt;br /&gt;
If the plugin requires login from the user at the time when they use it, then these functions can be used.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
Returns an array of the elements required in the login form. If no login form is required, then the default implementation of this will redirect to the files list. If $this-&amp;gt;options[&#039;ajax&#039;] is not set, then an HTML-snippet with the login fields (but not the form tags) should be output, instead of returning the form details.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login() { // From repository_alfresco&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $user_field = new stdClass();&lt;br /&gt;
        $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $user_field-&amp;gt;id    = &#039;alfresco_username&#039;;&lt;br /&gt;
        $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
        $user_field-&amp;gt;name  = &#039;al_username&#039;;&lt;br /&gt;
&lt;br /&gt;
        $passwd_field = new stdClass();&lt;br /&gt;
        $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;: &#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;id    = &#039;alfresco_password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
        $passwd_field-&amp;gt;name  = &#039;al_password&#039;;&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else { // Non-AJAX login form - directly output the form elements&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;al_username&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_alfresco&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;al_password&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Enter&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
For plugins that do not fully process the login via a popup window, the submitted details can be retrieved, from within the &#039;__construct&#039; function, via $submitted = optional_param(&#039;fieldname&#039;, [defaultvalue], PARAM_INT/PARAM_TEXT).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {&lt;br /&gt;
// Taken from repository_alfresco&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;alfresco = new Alfresco_Repository($this-&amp;gt;options[&#039;alfresco_url&#039;]);        &lt;br /&gt;
        $this-&amp;gt;username = optional_param(&#039;al_username&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        $this-&amp;gt;password = optional_param(&#039;al_password&#039;, &#039;&#039;, PARAM_RAW);&lt;br /&gt;
        try{&lt;br /&gt;
            // deal with user logging in&lt;br /&gt;
            if (empty($SESSION-&amp;gt;{$this-&amp;gt;sessname}) &amp;amp;&amp;amp; !empty($this-&amp;gt;username) &amp;amp;&amp;amp; !empty($this-&amp;gt;password)) {&lt;br /&gt;
                $this-&amp;gt;ticket = $this-&amp;gt;alfresco-&amp;gt;authenticate($this-&amp;gt;username, $this-&amp;gt;password);&lt;br /&gt;
                $SESSION-&amp;gt;{$this-&amp;gt;sessname} = $this-&amp;gt;ticket;&lt;br /&gt;
            } else {&lt;br /&gt;
                if (!empty($SESSION-&amp;gt;{$this-&amp;gt;sessname})) {&lt;br /&gt;
                    $this-&amp;gt;ticket = $SESSION-&amp;gt;{$this-&amp;gt;sessname};&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            $this-&amp;gt;user_session = $this-&amp;gt;alfresco-&amp;gt;createSession($this-&amp;gt;ticket);&lt;br /&gt;
            $this-&amp;gt;store = new SpacesStore($this-&amp;gt;user_session);&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $this-&amp;gt;logout();&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;current_node = null;&lt;br /&gt;
&lt;br /&gt;
/* Skipping code that is not relevant to user login */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Many types include a single element of type &#039;popup&#039; with the param &#039;url&#039; pointing at the URL used to authenticate the repo instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function print_login(){ // Code taken from repository_boxnet&lt;br /&gt;
    $t = $this-&amp;gt;boxclient-&amp;gt;getTicket();&lt;br /&gt;
    if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
        $popup_btn = new stdClass();&lt;br /&gt;
        $popup_btn-&amp;gt;type = &#039;popup&#039;;&lt;br /&gt;
        $popup_btn-&amp;gt;url = &#039; https://www.box.com/api/1.0/auth/&#039; . $t[&#039;ticket&#039;];&lt;br /&gt;
&lt;br /&gt;
        $ret = array();&lt;br /&gt;
        $ret[&#039;login&#039;] = array($popup_btn);&lt;br /&gt;
        return $ret;&lt;br /&gt;
    } else {&lt;br /&gt;
        echo &#039;&amp;lt;table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;boxusername&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;label&amp;gt;&#039;.get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;&amp;lt;/label&amp;gt;&amp;lt;/td&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;boxpassword&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;ticket&amp;quot; value=&amp;quot;&#039;.$t[&#039;ticket&#039;].&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;/table&amp;gt;&#039;;&lt;br /&gt;
        echo &#039;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&#039;.get_string(&#039;enter&#039;, &#039;repository&#039;).&#039;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function check_login() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    return !empty($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here. After this the code should return something suitable to display to the user (usually the results of calling $this-&amp;gt;print_login() ):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function logout() { // Taken from repository_alfresco&lt;br /&gt;
    global $SESSION;&lt;br /&gt;
    unset($SESSION-&amp;gt;{$this-&amp;gt;sessname});&lt;br /&gt;
    return $this-&amp;gt;print_login();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transferring files to Moodle (optional)===&lt;br /&gt;
These functions all relate to transferring the files into Moodle, once they have been chosen in the filepicker. All of them are optional and have default implementations which are often suitable to use as they are.&lt;br /&gt;
&lt;br /&gt;
====get_file_reference($source)====&lt;br /&gt;
Rarely does anything other than return the $source param (the default action if not overridden), but takes the &#039;source&#039; reference from the browser (originally specified in the list returned by &#039;get_listing&#039;) and makes sure it is ready to be passed on to the &#039;get_file&#039; or &#039;get_file_by_reference&#039; functions (below).&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $filename = &#039;&#039;)====&lt;br /&gt;
For FILE_INTERNAL or FILE_REFERENCE this function is called at the point when the user has clicked on the file and then on &#039;select this file&#039; to add it to the filemanager / editor element. It does the actual transfer of the file from the repository and onto the Moodle server. The default implementation is to download the $url via CURL. The $url parameter is the $reference returned by get_file_reference (above, but usually the same as the &#039;source&#039; returned by &#039;get_listing&#039;). The $filename should usually be processed by $path = $this-&amp;gt;prepare_file($filename), giving the full &#039;path&#039; where the file should be saved locally. This function then returns an array, containing:&lt;br /&gt;
* path - the local path where the file was saved&lt;br /&gt;
* url - the $url param passed into the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($url, $filename = &#039;&#039;) {&lt;br /&gt;
// Default implementation from the base &#039;repository&#039; class&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename); // Generate a unique temporary filename&lt;br /&gt;
    $c = new curl;&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_file($reference, $filename = &#039;&#039;) {&lt;br /&gt;
// Slightly extended version taken from repository_equella&lt;br /&gt;
    global $USER;&lt;br /&gt;
// Extract the details saved in the &#039;source&#039; param by &lt;br /&gt;
// repository/equella/callback.php (now in the $reference paramater)&lt;br /&gt;
    $ref = @unserialize(base64_decode($reference));&lt;br /&gt;
    if (!isset($ref-&amp;gt;url) || !($url = $this-&amp;gt;appendtoken($ref-&amp;gt;url))) {&lt;br /&gt;
        // Occurs when the user isn&#039;t known..&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
    $path = $this-&amp;gt;prepare_file($filename);&lt;br /&gt;
    $cookiepathname = $this-&amp;gt;prepare_file($USER-&amp;gt;id. &#039;_&#039;. uniqid(&#039;&#039;, true). &#039;.cookie&#039;);&lt;br /&gt;
    $c = new curl(array(&#039;cookie&#039;=&amp;gt;$cookiepathname));&lt;br /&gt;
    $result = $c-&amp;gt;download_one($url, null, array(&#039;filepath&#039; =&amp;gt; $path, &#039;followlocation&#039; =&amp;gt; true, &#039;timeout&#039; =&amp;gt; self::GETFILE_TIMEOUT));&lt;br /&gt;
    // Delete cookie jar.&lt;br /&gt;
    if (file_exists($cookiepathname)) {&lt;br /&gt;
        unlink($cookiepathname);&lt;br /&gt;
    }&lt;br /&gt;
    if ($result !== true) {&lt;br /&gt;
        throw new moodle_exception(&#039;errorwhiledownload&#039;, &#039;repository&#039;, &#039;&#039;, $result);&lt;br /&gt;
    }&lt;br /&gt;
    return array(&#039;path&#039;=&amp;gt;$path, &#039;url&#039;=&amp;gt;$url);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36786</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36786"/>
		<updated>2012-12-05T12:08:30Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* updating the filepicker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
==get_listing==&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;&#039;type&#039;&#039;&#039; and &#039;&#039;&#039;src&#039;&#039;&#039; elements and the presence of the &#039;&#039;&#039;callbackurl&#039;&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
==updating the filepicker==&lt;br /&gt;
When the Equella file chooser has finished working, it then needs to update the Moodle filepicker with the details of the chosen file. It does this by redirecting the OBJECT to the &#039;&#039;&#039;callbackurl&#039;&#039;&#039; specified in the original &#039;&#039;url&#039;&#039; parameters.&lt;br /&gt;
This callback script (which, in the case of the Equella respository type, points to repository/equella/callback.php) extracts the details of the file returned and then outputs a small bit of javascript to update the filepicker:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(dirname(dirname(dirname(__FILE__))).&#039;/config.php&#039;);&lt;br /&gt;
&lt;br /&gt;
// Extract and decode the return value&lt;br /&gt;
$json = required_param(&#039;tlelinks&#039;, PARAM_RAW);&lt;br /&gt;
require_login();&lt;br /&gt;
$decodedinfo = json_decode($json);&lt;br /&gt;
$info = array_pop($decodedinfo);&lt;br /&gt;
$url = &#039;&#039;;&lt;br /&gt;
if (isset($info-&amp;gt;url)) {&lt;br /&gt;
    $url = s(clean_param($info-&amp;gt;url, PARAM_URL));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Omitted the extracting and cleaning of the other parameters - filename, author, etc. */&lt;br /&gt;
&lt;br /&gt;
$source = base64_encode(serialize((object)array(&#039;url&#039;=&amp;gt;$url,&#039;filename&#039;=&amp;gt;$filename)));&lt;br /&gt;
&lt;br /&gt;
// Generate some javascript to update the filepicker with the details of the file selected&lt;br /&gt;
$js =&amp;lt;&amp;lt;&amp;lt;EOD&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
   &amp;lt;meta http-equiv=&amp;quot;content-type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    window.onload = function() {&lt;br /&gt;
        var resource = {};&lt;br /&gt;
        resource.title = &amp;quot;$filename&amp;quot;;&lt;br /&gt;
        resource.source = &amp;quot;$source&amp;quot;;&lt;br /&gt;
        resource.thumbnail = &#039;$thumbnail&#039;;&lt;br /&gt;
        resource.author = &amp;quot;$author&amp;quot;;&lt;br /&gt;
        resource.license = &amp;quot;$license&amp;quot;;&lt;br /&gt;
        parent.M.core_filepicker.select_file(resource);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;noscript&amp;gt;&amp;lt;/noscript&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
EOD;&lt;br /&gt;
&lt;br /&gt;
// Output the generated javascript&lt;br /&gt;
header(&#039;Content-Type: text/html; charset=utf-8&#039;);&lt;br /&gt;
die($js);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After this, the rest of the repository API functions (e.g. get_file) can operate as usual on the &#039;&#039;&#039;source&#039;&#039;&#039; returned to the filepicker.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36785</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36785"/>
		<updated>2012-12-05T12:00:45Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
==get_listing==&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;&#039;type&#039;&#039;&#039; and &#039;&#039;&#039;src&#039;&#039;&#039; elements and the presence of the &#039;&#039;&#039;callbackurl&#039;&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
==updating the filepicker==&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36784</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36784"/>
		<updated>2012-12-05T12:00:23Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* updating the filepicker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;&#039;type&#039;&#039;&#039; and &#039;&#039;&#039;src&#039;&#039;&#039; elements and the presence of the &#039;&#039;&#039;callbackurl&#039;&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36783</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36783"/>
		<updated>2012-12-05T11:57:53Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* get_listing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;&#039;type&#039;&#039;&#039; and &#039;&#039;&#039;src&#039;&#039;&#039; elements and the presence of the &#039;&#039;&#039;callbackurl&#039;&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36782</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36782"/>
		<updated>2012-12-05T11:57:40Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* get_listing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;&#039;type&#039;&#039;&#039; and &#039;&#039;&#039;src&#039;&#039;&#039; elements and the presence of the &#039;&#039;callbackurl&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36781</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36781"/>
		<updated>2012-12-05T11:57:23Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* get_listing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
The returned array should return an &#039;object&#039; element, containing the following:&lt;br /&gt;
* type - a string with the mime type of the item to display (e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;)&lt;br /&gt;
* url - a string with the website address to embed in the object&lt;br /&gt;
&lt;br /&gt;
This will replace the usual filepicker list of files with an OBJECT html tag:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;object type=&amp;quot;[type]&amp;quot; src=&amp;quot;[url]&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of generating this can be found in the Equella plugin:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_listing($path = null, $page = null) {&lt;br /&gt;
    global $COURSE;&lt;br /&gt;
    $callbackurl = new moodle_url(&#039;/repository/equella/callback.php&#039;, array(&#039;repo_id&#039;=&amp;gt;$this-&amp;gt;id));&lt;br /&gt;
    $mimetypesstr = &#039;&#039;;&lt;br /&gt;
    $restrict = &#039;&#039;;&lt;br /&gt;
    if (!empty($this-&amp;gt;mimetypes)) {&lt;br /&gt;
        $mimetypesstr = &#039;&amp;amp;mimeTypes=&#039; . implode(&#039;,&#039;, $this-&amp;gt;mimetypes);&lt;br /&gt;
        // We&#039;re restricting to a mime type, so we always restrict to selecting resources only.&lt;br /&gt;
        $restrict = &#039;&amp;amp;attachmentonly=true&#039;;&lt;br /&gt;
    } else if ($this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) != &#039;none&#039;) {&lt;br /&gt;
        // The option value matches the EQUELLA paramter name.&lt;br /&gt;
        $restrict = &#039;&amp;amp;&#039; . $this-&amp;gt;get_option(&#039;equella_select_restriction&#039;) . &#039;=true&#039;;&lt;br /&gt;
    }&lt;br /&gt;
    $url = $this-&amp;gt;get_option(&#039;equella_url&#039;)&lt;br /&gt;
            . &#039;?method=lms&#039;&lt;br /&gt;
            . &#039;&amp;amp;returnurl=&#039;.urlencode($callbackurl)&lt;br /&gt;
            . &#039;&amp;amp;returnprefix=tle&#039;&lt;br /&gt;
            . &#039;&amp;amp;template=standard&#039;&lt;br /&gt;
            . &#039;&amp;amp;token=&#039;.urlencode($this-&amp;gt;getssotoken(&#039;write&#039;))&lt;br /&gt;
            . &#039;&amp;amp;courseId=&#039;.urlencode($COURSE-&amp;gt;idnumber)&lt;br /&gt;
            . &#039;&amp;amp;courseCode=&#039;.urlencode($COURSE-&amp;gt;shortname)&lt;br /&gt;
            . &#039;&amp;amp;action=searchThin&#039;&lt;br /&gt;
            . &#039;&amp;amp;forcePost=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;cancelDisabled=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;attachmentUuidUrls=true&#039;&lt;br /&gt;
            . &#039;&amp;amp;options=&#039;.urlencode($this-&amp;gt;get_option(&#039;equella_options&#039;) . $mimetypesstr)&lt;br /&gt;
            . $restrict;&lt;br /&gt;
    $list = array();&lt;br /&gt;
    $list[&#039;object&#039;] = array();&lt;br /&gt;
    $list[&#039;object&#039;][&#039;type&#039;] = &#039;text/html&#039;;&lt;br /&gt;
    $list[&#039;object&#039;][&#039;src&#039;] = $url;&lt;br /&gt;
    $list[&#039;nologin&#039;]  = true;&lt;br /&gt;
    $list[&#039;nosearch&#039;] = true;&lt;br /&gt;
    $list[&#039;norefresh&#039;] = true;&lt;br /&gt;
    return $list;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note particularly the object param with the &#039;&#039;type&#039;&#039; and &#039;&#039;src&#039;&#039; elements and the presence of the &#039;&#039;callbackurl&#039;&#039; in the parameters passed to Equella. This is covered in more detail in the section below.&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36780</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36780"/>
		<updated>2012-12-05T11:48:34Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Database Tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_database&amp;diff=36779</id>
		<title>Repository plugins database</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_database&amp;diff=36779"/>
		<updated>2012-12-05T11:48:26Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&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;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_database&amp;diff=36778</id>
		<title>Repository plugins database</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_database&amp;diff=36778"/>
		<updated>2012-12-05T11:48:02Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;== repository ==  {| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; |&amp;#039;&amp;#039;&amp;#039;Field&amp;#039;&amp;#039;&amp;#039;  |&amp;#039;&amp;#039;&amp;#039;Type&amp;#039;&amp;#039;&amp;#039;  |&amp;#039;&amp;#039;&amp;#039;Default&amp;#039;&amp;#039;&amp;#039;  |&amp;#039;&amp;#039;&amp;#039;Info&amp;#039;&amp;#039;&amp;#039;   |- |&amp;#039;&amp;#039;&amp;#039;id&amp;#039;&amp;#039;&amp;#039; |int(10) | |autoincrementing   |- |&amp;#039;&amp;#039;&amp;#039;type&amp;#039;&amp;#039;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Template:Repository_plugins&amp;diff=36777</id>
		<title>Template:Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Template:Repository_plugins&amp;diff=36777"/>
		<updated>2012-12-05T11:47:17Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;sideblock right&amp;quot; style=&amp;quot;width: 16em;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;Repository plugins&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Repository plugin files]]&lt;br /&gt;
* [[Repository plugins embedding external file chooser|External file chooser]]&lt;br /&gt;
* [[Repository plugins database|Database tables]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36776</id>
		<title>Repository plugin files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36776"/>
		<updated>2012-12-05T11:45:12Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
This is an overview of the files that are found within [[Repository plugins]].&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lib.php&#039;&#039;&#039; - this contains the core functionality for your plugin. Within it you must define a class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class repository_myplugin extends repository {&lt;br /&gt;
  // See [[Repository plugins]] for a list of functions to override in here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;pix/icon.png&#039;&#039;&#039; - an icon to display in the file picker (16x16)&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;[[version.php]]&#039;&#039;&#039; - contains the current version number of the plugin and other important details ( https://docs.moodle.org/dev/version.php )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$plugin-&amp;gt;version = 2012061700; //The current plugin version (Date: YYYYMMDDXX)&lt;br /&gt;
$plugin-&amp;gt;requires = 2012061700;  //Requires this Moodle version&lt;br /&gt;
$plugin-&amp;gt;component = &#039;repository_myplugin&#039;; //Full name of the plugin (used for diagnostics)&lt;br /&gt;
$plugin-&amp;gt;cron = 0; // How often to run automatic updates (0 to disable)&lt;br /&gt;
$plugin-&amp;gt;release = &#039;Human-readable version number&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; - contains the English language strings for display by your plugin. As a minimum, this must include:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Configuration for my plugin repository&#039;;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;My plugin repository&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A few more details about my repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;db/access.php&#039;&#039;&#039; - defines any user capabilities related to the plugin. A basic access.php file will look like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;repository/myplugin:view&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW &lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the capabilities have been defined, it is good practice to add a language string for them to the &#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;myplugin:view&#039;] = &#039;View the myplugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36775</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36775"/>
		<updated>2012-12-05T11:43:45Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36774</id>
		<title>Repository plugin files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36774"/>
		<updated>2012-12-05T11:43:12Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
This is an overview of the files that are found within [[Repository plugins]].&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lib.php&#039;&#039;&#039; - this contains the core functionality for your plugin. Within it you must define a class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class repository_myplugin extends repository {&lt;br /&gt;
  // See [[Repository plugins]] for a list of functions to override in here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;pix/icon.png&#039;&#039;&#039; - an icon to display in the file picker (16x16)&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;[[version.php]]&#039;&#039;&#039; - contains the current version number of the plugin and other important details ( https://docs.moodle.org/dev/version.php )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$plugin-&amp;gt;version = 2012061700; //The current plugin version (Date: YYYYMMDDXX)&lt;br /&gt;
$plugin-&amp;gt;requires = 2012061700;  //Requires this Moodle version&lt;br /&gt;
$plugin-&amp;gt;component = &#039;repository_myplugin&#039;; //Full name of the plugin (used for diagnostics)&lt;br /&gt;
$plugin-&amp;gt;cron = 0; // How often to run automatic updates (0 to disable)&lt;br /&gt;
$plugin-&amp;gt;release = &#039;Human-readable version number&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; - contains the English language strings for display by your plugin. As a minimum, this must include:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;My plugin repository&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Configuration for my plugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;db/access.php&#039;&#039;&#039; - defines any user capabilities related to the plugin. A basic access.php file will look like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;repository/myplugin:view&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW &lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the capabilities have been defined, it is good practice to add a language string for them to the &#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;myplugin:view&#039;] = &#039;View the myplugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36773</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36773"/>
		<updated>2012-12-05T11:42:49Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Repository plugins}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Template:Repository_plugins&amp;diff=36772</id>
		<title>Template:Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Template:Repository_plugins&amp;diff=36772"/>
		<updated>2012-12-05T11:42:17Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;&amp;lt;div class=&amp;quot;sideblock right&amp;quot; style=&amp;quot;width: 16em;&amp;quot;&amp;gt; &amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;Repository plugins&amp;lt;/div&amp;gt; &amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt; * Repository plugins * Repository plugin files * [[R...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;sideblock right&amp;quot; style=&amp;quot;width: 16em;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;Repository plugins&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Repository plugin files]]&lt;br /&gt;
* [[Repository plugins embedding external file chooser|External file chooser]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36770</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36770"/>
		<updated>2012-12-05T11:11:26Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Administration APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/**&lt;br /&gt;
 * repository_flickr_public class&lt;br /&gt;
 * Moodle user can access public flickr account&lt;br /&gt;
 *&lt;br /&gt;
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
*/&lt;br /&gt;
class repository_flickr_public extends repository {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36769</id>
		<title>Repository plugins embedding external file chooser</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins_embedding_external_file_chooser&amp;diff=36769"/>
		<updated>2012-12-05T11:06:30Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;By making use of the &amp;#039;object&amp;#039; tag within the return of the &amp;#039;get_listing&amp;#039; function, Repository plugins are able to embed an external file chooser within the repository panel. ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;By making use of the &#039;object&#039; tag within the return of the &#039;get_listing&#039; function, [[Repository plugins]] are able to embed an external file chooser within the repository panel.  This allows for more customisation of the interface, than is allowed by simply returning a list of the available files.&lt;br /&gt;
The Equella plugin is an example of doing this.&lt;br /&gt;
&lt;br /&gt;
=get_listing=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=updating the filepicker=&lt;br /&gt;
&#039;&#039;TODO: complete this&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36768</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36768"/>
		<updated>2012-12-05T11:01:23Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Functions you *MUST* override */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
&lt;br /&gt;
These functions cover the basics of initialising your plugin each time the repository is accessed and listing the files available to the user from within the plugin.&lt;br /&gt;
&lt;br /&gt;
====__construct($respoitoryid, $context=SYSCONTEXTID, $options=array(), $readonly=0)====&lt;br /&gt;
Should be overridden to do any initialisation required by the repository, including:&lt;br /&gt;
* logging in via optional_param, if required - see &#039;print_login&#039;, below&lt;br /&gt;
* getting any options from the database&lt;br /&gt;
&lt;br /&gt;
The possible items in the $options array are:&lt;br /&gt;
* &#039;ajax&#039; - bool, true if the user is using the AJAX filepicker&lt;br /&gt;
* &#039;mimetypes&#039; - array of accepted mime types, or &#039;*&#039; for all types&lt;br /&gt;
&lt;br /&gt;
Calling parent::__construct($repositoryid, $context, $options, $readonly); is essential and will set up various required member variables:&lt;br /&gt;
* $this-&amp;gt;id - the repository instance id (the ID of the entry in mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;context - the context in which the repository instance can be found&lt;br /&gt;
* $this-&amp;gt;instance - the repository instance record (from mdl_repository_instances)&lt;br /&gt;
* $this-&amp;gt;readonly - whether or not the settings can be changed&lt;br /&gt;
* $this-&amp;gt;options - the above options, combined with the settings saved in the database&lt;br /&gt;
* $this-&amp;gt;name - as specified by $this-&amp;gt;get_name()&lt;br /&gt;
* $this-&amp;gt;returntypes - as specified by $this-&amp;gt;supported_returntypes()&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files to be displayed to the user, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Amongst other details, this returns a &#039;&#039;&#039;title&#039;&#039;&#039; for each file (to be displayed in the filepicker) and the &#039;&#039;&#039;source&#039;&#039;&#039; for the file (which will be included in the request to &#039;download&#039; the file into Moodle or to generate a link to the file). Directories return a &#039;&#039;&#039;children&#039;&#039;&#039; value, which is either an empty array (if &#039;dynload&#039; is specified) or an array of the files and directories contained within it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
// The &#039;object&#039; tag can be used to embed an external web page or application within the filepicker&lt;br /&gt;
   &#039;object&#039; =&amp;gt; array(&lt;br /&gt;
      &#039;type&#039; =&amp;gt; (string) e.g. &#039;text/html&#039;, &#039;application/x-shockwave-flash&#039;&lt;br /&gt;
      &#039;url&#039; =&amp;gt; (string) the website address to embed in the object&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
The use of the &#039;&#039;&#039;object&#039;&#039;&#039; tag, instead of returning a &#039;&#039;list&#039;&#039; of files, allows you to embed an external file chooser within the repository panel. See [[Repository plugins embedding external file chooser]] for details about how to do this.&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36767</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36767"/>
		<updated>2012-12-05T10:35:14Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* plugin_init() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36766</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36766"/>
		<updated>2012-12-05T10:34:39Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* plugin_init() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Example of using the settings===&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36765</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36765"/>
		<updated>2012-12-05T10:33:32Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Instance settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository). All of these are optional, without them, the instance settings form will only contain a single &#039;name&#039; field.&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36764</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36764"/>
		<updated>2012-12-05T10:32:40Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Global settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
Optional. This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Optional. Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36763</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36763"/>
		<updated>2012-12-05T10:31:38Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Administration APIs */ Rearranged and expanded the explanations slightly&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Fixed settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are hard-coded into your repository plugin and can only be updated by changing the plugin code.&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
Return any combination of the following values:&lt;br /&gt;
* FILE_INTERNAL - the file is uploaded/downloaded and stored directly within the Moodle file system&lt;br /&gt;
* FILE_EXTERNAL - the file stays in the external repository and is accessed from there directly&lt;br /&gt;
* FILE_REFERENCE - the file may be cached locally, but is automatically synchronised, as required, with any changes to the external original&lt;br /&gt;
The type used by Moodle depends on the choices made by the end user (e.g. inserting a link, will result in &#039;FILE_EXTERNAL&#039;-related functions being used, using a &#039;shortcut/alias&#039; will result in the &#039;FILE_REFERENCE&#039;-related functions being used).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_returntypes() {&lt;br /&gt;
    return FILE_REFERENCE|FILE_INTERNAL|FILE_EXTERNAL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
Optional. Returns &#039;*&#039; for all file types (default implementation), or an array of types or groups (e.g. array(&#039;text/plain&#039;, &#039;image/gif&#039;, &#039;web_image&#039;) )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function supported_filetypes() {&lt;br /&gt;
    //return &#039;*&#039;;&lt;br /&gt;
    //return array(&#039;image/gif&#039;, &#039;image/jpeg&#039;, &#039;image/png&#039;);&lt;br /&gt;
    return array(&#039;web_image&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For a full list of possible types and groups, look in lib/filelib.php, function get_mimetypes_array().&lt;br /&gt;
&lt;br /&gt;
===Global settings===&lt;br /&gt;
&lt;br /&gt;
These are settings that are configured for the whole Moodle site and not per instance of your plugin. All of these are optional, without them there will be no configuration options in the Site administration &amp;gt; Plugins &amp;gt; Repositories &amp;gt; Myplugin page.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Optional. Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
   return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form($mform, $classname=&#039;repository&#039;)====&lt;br /&gt;
This is for modifying the Moodle form displaying the plugin settings. [[lib/formslib.php Form Definition]] has details of all the types of elements you can add to the settings form.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
    parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
    $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Use this function if you need to validate some variables submitted by plugin settings form. To use it, check through the associative array of data provided (&#039;settingname&#039; =&amp;gt; value) for any errors. Then push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;human readable error message&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
        $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Instance settings===&lt;br /&gt;
These functions relate to a specific instance of your plugin (e.g. the URL and login details to access a specific webdav repository).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array. This is equivalent to &#039;&#039;get_type_option_names()&#039;&#039;, but for a specific instance.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_instance_option_names() {&lt;br /&gt;
    return array(&#039;fs_path&#039;); // From repository_filesystem&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====instance_config_form($mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance. This is equivalent to &#039;&#039;type_config_form($mform, $classname)&#039;&#039; but for instances.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
This allows us to validate what has been submitted in the instance configuration form. This is equivalent to &#039;&#039;type_form_validation($mform, $data, $errors), but for instances. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
    if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
        $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Getting / updating settings====&lt;br /&gt;
&lt;br /&gt;
Both global and instance settings can be retrieved, from within the plugin, via $this-&amp;gt;get_option(&#039;settingname&#039;) and updated via $this-&amp;gt;set_option(array(&#039;settingname&#039; =&amp;gt; &#039;value&#039;)).&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36762</id>
		<title>Repository plugin files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36762"/>
		<updated>2012-12-05T10:07:37Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is an overview of the files that are found within [[Repository plugins]].&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lib.php&#039;&#039;&#039; - this contains the core functionality for your plugin. Within it you must define a class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class repository_myplugin extends repository {&lt;br /&gt;
  // See [[Repository plugins]] for a list of functions to override in here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;pix/icon.png&#039;&#039;&#039; - an icon to display in the file picker (16x16)&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;[[version.php]]&#039;&#039;&#039; - contains the current version number of the plugin and other important details ( https://docs.moodle.org/dev/version.php )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$plugin-&amp;gt;version = 2012061700; //The current plugin version (Date: YYYYMMDDXX)&lt;br /&gt;
$plugin-&amp;gt;requires = 2012061700;  //Requires this Moodle version&lt;br /&gt;
$plugin-&amp;gt;component = &#039;repository_myplugin&#039;; //Full name of the plugin (used for diagnostics)&lt;br /&gt;
$plugin-&amp;gt;cron = 0; // How often to run automatic updates (0 to disable)&lt;br /&gt;
$plugin-&amp;gt;release = &#039;Human-readable version number&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; - contains the English language strings for display by your plugin. As a minimum, this must include:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;My plugin repository&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Configuration for my plugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;db/access.php&#039;&#039;&#039; - defines any user capabilities related to the plugin. A basic access.php file will look like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;repository/myplugin:view&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW &lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the capabilities have been defined, it is good practice to add a language string for them to the &#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;myplugin:view&#039;] = &#039;View the myplugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36761</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugins&amp;diff=36761"/>
		<updated>2012-12-05T10:07:24Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Repository plugin allow Moodle to bring contents into Moodle from external repositories.&lt;br /&gt;
&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
Repository plugins exists from 2.0&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
*[[Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
There is a template available in [https://github.com/dongsheng/moodle-repository_demo Dongsheng Cai&#039;s github]&lt;br /&gt;
&lt;br /&gt;
==Creating new repository plugin==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/repository/&#039;&#039; e.g. &#039;&#039;/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files in your plugin folder:&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/pix/icon.png&#039;&#039; - the icon displayed in the file picker (16x16)&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/[[version.php]]&#039;&#039;&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; - language file&lt;br /&gt;
#* &#039;&#039;/repository/myplugin/db/access.php&#039;&#039;&lt;br /&gt;
# Declare class &#039;&#039;&#039;repository_myplugin extends repository&#039;&#039;&#039; in your lib.php&lt;br /&gt;
# In your repository_myplugin class overwrite function get_listing() to &#039;&#039;&#039;return array(&#039;list&#039; =&amp;gt; array());&#039;&#039;&#039;&lt;br /&gt;
# Add at least strings &#039;&#039;&#039;$string[&#039;pluginname&#039;]&#039;&#039;&#039; and &#039;&#039;&#039;$string[&#039;configplugin&#039;]&#039;&#039;&#039; to your language file&lt;br /&gt;
# Add capability &#039;repository/myplugin:view&#039; to your access.php file&lt;br /&gt;
# Create install and upgrade scripts (optional or you can do it later)&lt;br /&gt;
# Login as admin on your website and run upgrade&lt;br /&gt;
# Open Site Administration-&amp;gt;Plugins-&amp;gt;Repositories-&amp;gt;Manage Repositories and make your repository &#039;Enabled and visible&#039;&lt;br /&gt;
&lt;br /&gt;
For a more detailed explanation of each of each of the files that have been created here, along with code examples, see [[Repository plugin files]].&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
All of the following functions are optional. If they&#039;re not implemented, your plugin will not have manual settings and will have only one instance displayed in the File Picker (The repository API creates this unique instance when the administrator add the plugin).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====instance_form_validation($mform, $data, $errors)====&lt;br /&gt;
This allows us to validate what has been submitted in the instance configuration form. For instance:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function instance_form_validation($mform, $data, $errors) {&lt;br /&gt;
        if (empty($data[&#039;email_address&#039;])) {&lt;br /&gt;
            $errors[&#039;email_address&#039;] = get_string(&#039;invalidemailsettingname&#039;, &#039;repository_flickr_public&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return $errors;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function return an empty array.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_type_option_names() {&lt;br /&gt;
        return array_merge(parent::get_type_option_names(), array(&#039;rootpath&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the plugin settings.&lt;br /&gt;
&lt;br /&gt;
For example, to display the standard repository plugin settings along with the custom ones use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function type_config_form($mform) {&lt;br /&gt;
        parent::type_config_form($mform);&lt;br /&gt;
&lt;br /&gt;
        $rootpath = get_config(&#039;repository_someplugin&#039;, &#039;rootpath&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;rootpath&#039;, get_string(&#039;rootpath&#039;, &#039;repository_someplugin&#039;), array(&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;rootpath&#039;, $rootpath);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====type_form_validation($mform, $data, $errors)====&lt;br /&gt;
Use this function if you need to validate some variables submitted by plugin settings form. Push the items to $error array in the format (&amp;quot;fieldname&amp;quot; =&amp;gt; &amp;quot;errormessage&amp;quot;) to have them highlighted in the form.&lt;br /&gt;
&lt;br /&gt;
With the example above, this function may look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function type_form_validation($mform, $data, $errors) {&lt;br /&gt;
        if (!is_dir($data[&#039;rootpath&#039;])) {&lt;br /&gt;
            $errors[&#039;rootpath&#039;] = get_string(&#039;invalidrootpath&#039;, &#039;repository_someplugin&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return $errors;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
==Repository APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
* Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;? If they do, in your plugin you have to detect user session in constructor() function, and use print_login() if required, see more details below.&lt;br /&gt;
* For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function, see more details below.&lt;br /&gt;
* You wanna retrieve the file that the user selected, rewrite get_file() if required, see more details below.&lt;br /&gt;
* Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;, if they do, you will have to rewrite search() method, see more details below.&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;10451213&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;1340002147&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // &#039;path&#039; is used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // &#039;dynload&#039; tells file picker to fetch list dynamically.&lt;br /&gt;
   // When user clicks the folder, it will send a ajax request to server side.&lt;br /&gt;
   // Default value is false but note that non-Javascript file picker always acts as if dynload was set to true&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be set.&lt;br /&gt;
   // It is not recommended to use pagination and subfolders at the same time, the tree view mode can not handle it correctly&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (int) how many pages. If number of pages is unknown but we know that the next page exists repository may return -1&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url to file manager for the external repository, if specified will display link in file picker&lt;br /&gt;
   &#039;help&#039; =&amp;gt; (string) url to the help window, if specified will display link in file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login, default false, if set to true the login link will be removed from file picker&lt;br /&gt;
   &#039;norefresh&#039; =&amp;gt; (bool) no refresh button, default false&lt;br /&gt;
   &#039;logouttext&#039; =&amp;gt; (string) in case of nologin=false can substitute the text &#039;Logout&#039; for logout link in file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link, default false, if set to true the search link will be removed from file picker&lt;br /&gt;
   &#039;issearchresult&#039; =&amp;gt; (bool) tells that this listing is the result of search&lt;br /&gt;
   // for repositories that actually upload a file: set &#039;upload&#039; option to display an upload form in file picker&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // &#039;list&#039; is used by file picker to build a file/folder tree&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (int) UNIX timestamp, default value for datemodified and datecreated,&lt;br /&gt;
       &#039;datemodified&#039; =&amp;gt; (int) UNIX timestamp when the file was last modified [2.3+],&lt;br /&gt;
       &#039;datecreated&#039; =&amp;gt; (int) UNIX timestamp when the file was last created [2.3+],&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size in bytes,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;thumbnail_height&#039; =&amp;gt; (int) the height of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039; =&amp;gt; the accessible url of file,&lt;br /&gt;
       &#039;icon&#039; =&amp;gt; (string) url to icon of the image (24x24px), if omitted the moodle filetype icon will be used [2.3+],&lt;br /&gt;
       &#039;realthumbnail&#039; =&amp;gt; (string) url to image preview to be lazy-loaded when scrolled to it (if it requires to be generated and can not be returned as &#039;thumbnail&#039;) [2.3+],&lt;br /&gt;
       &#039;realicon&#039; =&amp;gt; (string) url to image preview in icon size (24x24) [2.3+],&lt;br /&gt;
       &#039;author&#039; =&amp;gt; (string) default value for file author,&lt;br /&gt;
       &#039;license&#039; =&amp;gt; (string) default value for license (short name, see class license_manager),&lt;br /&gt;
       &#039;image_height&#039; =&amp;gt; (int) if the file is an image, image height in pixels, null otherwise [2.3+],&lt;br /&gt;
       &#039;image_width&#039; =&amp;gt;  (int) if the file is an image, image width in pixels, null otherwise [2.3+]&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - similar to file, has also &#039;path&#039; and &#039;children&#039; but no &#039;source&#039; or &#039;url&#039;&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder. In case of dynload=true (and for non-JS filepicker) the value will be passed to repository_xxx::get_listing() in order to retrieve children&lt;br /&gt;
       &#039;date&#039;, &#039;datemodified&#039;, &#039;datecreated&#039;, &#039;thumbnail&#039;, &#039;icon&#039; =&amp;gt; see above,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( &lt;br /&gt;
         // presence of this attribute actually tells file picker that this is a folder. In case of dynload=true, it should be empty array&lt;br /&gt;
         // otherwise it is a nested list of contained files and folders&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path only instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====get_file_source_info (2.3+)====&lt;br /&gt;
Returns the value to be stored in files.source field in DB (regardless whether file is picked as a copy or by reference). It indicates where the file came from. It is advised to include either full URL here or indication of the repository.&lt;br /&gt;
Examples: &#039;Dropbox: /filename.jpg&#039;, &#039;http://fullurl.com/path/file&#039;, etc.&lt;br /&gt;
This value will be used to display warning message if reference can not be restored from backup.  Also it can (although not has to) be used in get_reference_details() to produce the human-readable reference source in the fileinfo dialogue in the file manager.&lt;br /&gt;
&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field = new stdClass();&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field = new stdClass();&lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
&lt;br /&gt;
A custom search form must include the following:&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;repo_id&#039;&#039;&#039; and the value must be the id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;ctx_id&#039;&#039;&#039; and the value must be the context id of the repository instance&lt;br /&gt;
* A hidden element named &#039;&#039;&#039;sesskey&#039;&#039;&#039; and the value must be the session key&lt;br /&gt;
* A text field element named &#039;&#039;&#039;s&#039;&#039;&#039;, this is where users will type in their search criteria&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class repository_myrepo extends repository {&lt;br /&gt;
    // other required functions&lt;br /&gt;
    ....&lt;br /&gt;
&lt;br /&gt;
    public function search($search_text, $page = 0) { // Since Moodle 2.3, the page argument is required&lt;br /&gt;
&lt;br /&gt;
        // Hidden field repo instance id&lt;br /&gt;
        $attributes = array(&#039;type&#039;=&amp;gt;&#039;hidden&#039;,&lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;repo_id&#039;,&lt;br /&gt;
                            &#039;value&#039; =&amp;gt; $this-&amp;gt;id);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field context id&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;ctx_id&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = $this-&amp;gt;context-&amp;gt;id;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // hidden field session key&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;sesskey&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = sesskey();&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
&lt;br /&gt;
        // label search name&lt;br /&gt;
        $param = array(&#039;for&#039; =&amp;gt; &#039;label_search_name&#039;);&lt;br /&gt;
        $title = get_string(&#039;search_name&#039;, &#039;myrepo_search_name&#039;);&lt;br /&gt;
        $html .= html_writer::tag(&#039;label&#039;, $title, $param);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
&lt;br /&gt;
        // text field search name&lt;br /&gt;
        $attributes[&#039;type&#039;] = &#039;text&#039;;&lt;br /&gt;
        $attributes[&#039;name&#039;] = &#039;s&#039;;&lt;br /&gt;
        $attributes[&#039;value&#039;] = &#039;&#039;;&lt;br /&gt;
        $attributes[&#039;title&#039;] = $title;&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;input&#039;, $attributes);&lt;br /&gt;
        $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the forum you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
===Repository support for returning file as alias/shortcut===&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.3 it became possible to link to the file from external (or internal) repository by reference. In UI it is called “create alias/shortcut”. This creates a row in {files} table but the contents of the file is not stored. Although it may be cached by repository if developer wants to.&lt;br /&gt;
&lt;br /&gt;
Make sure that function supported_returntypes() returns FILE_REFERENCE among other types.&lt;br /&gt;
&lt;br /&gt;
Note that external file is synchronised by moodle when UI wants to show the file size.&lt;br /&gt;
&lt;br /&gt;
====get_reference_details====&lt;br /&gt;
When file in moodle filearea is a reference to file in some repository, filemanager can display the location of the original. This function is responsible for returning human-readable location. It is usually prefixed with repository name and semicolon.&lt;br /&gt;
&lt;br /&gt;
====get_reference_file_lifetime====&lt;br /&gt;
how often to synchronise the file&lt;br /&gt;
&lt;br /&gt;
====sync_individual_file====&lt;br /&gt;
Decide whether or not the file should be synced (by default true). This is checked after the lifetime is checked.&lt;br /&gt;
&lt;br /&gt;
====get_file_by_reference====&lt;br /&gt;
This is actual synchronisation performed when sync conditions are met. Note that it is not necessary to download file here. This is just needed to find out if filesize and/or contenthash have changed since the last synchronization.&lt;br /&gt;
This function returns null if source file can not be found any more.&lt;br /&gt;
Otherwise it returns an object with file information (see phpdocs). The preferable output is only contenthash/filesize: if repository is able to retrieve this information without downloading file into moodle it is the best. Don’t forget that this function might be called quite often since filemanager always wants to know the file size.&lt;br /&gt;
&lt;br /&gt;
====send_file====&lt;br /&gt;
Repository method to serve the referenced file. This function is called when user actually tries to download/view the file. But it still can return the cached copy if repository developer wishes so.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;pluginname_help&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Database 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;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Plugins]]&lt;br /&gt;
*[[Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36760</id>
		<title>Repository plugin files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_plugin_files&amp;diff=36760"/>
		<updated>2012-12-05T10:05:06Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;This is an overview of the files that are found within Repository plugins. * /repository/myplugin/&amp;#039;&amp;#039;&amp;#039;lib.php&amp;#039;&amp;#039;&amp;#039; - this contains the core functionality for your plugin. Within...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is an overview of the files that are found within [[Repository plugins]].&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lib.php&#039;&#039;&#039; - this contains the core functionality for your plugin. Within it you must define a class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class repository_myplugin extends repository {&lt;br /&gt;
  // See [[Repository plugins]] for a list of functions to override in here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;pix/icon.png&#039;&#039;&#039; - an icon to display in the file picker (16x16)&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;[[version.php]]&#039;&#039;&#039; - contains the current version number of the plugin and other important details ( https://docs.moodle.org/dev/version.php )&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$plugin-&amp;gt;version = 2012061700; //The current plugin version (Date: YYYYMMDDXX)&lt;br /&gt;
$plugin-&amp;gt;requires = 2012061700;  //Requires this Moodle version&lt;br /&gt;
$plugin-&amp;gt;component = &#039;repository_myplugin&#039;; //Full name of the plugin (used for diagnostics)&lt;br /&gt;
$plugin-&amp;gt;cron = 0; // How often to run automatic updates (0 to disable)&lt;br /&gt;
$plugin-&amp;gt;release = &#039;Human-readable version number&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;lang/en/repository_myplugin.php&#039;&#039;&#039; - contains the English language strings for display by your plugin. As a minimum, this must include:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;My plugin repository&#039;;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Configuration for my plugin repository&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* /repository/myplugin/&#039;&#039;&#039;db/access.php&#039;&#039;&#039; - defines any user capabilities related to the plugin. A basic access.php file will look like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;repository/myplugin:view&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW &lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Repository plugins]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=version.php&amp;diff=34357</id>
		<title>version.php</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=version.php&amp;diff=34357"/>
		<updated>2012-07-02T19:36:46Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This file is included in the main directory of plugin. It is compulsory for most plugin types. Even when not compulsory it is highly recommended. &lt;br /&gt;
&lt;br /&gt;
It contains a number of fields, which are used during the install / upgrade process to make sure the plugin is compatible with the current Moodle install, as well as spotting whether an upgrade is needed.&lt;br /&gt;
&lt;br /&gt;
The file is a standard PHP file, starting with an opening &#039;&amp;amp;lt;?php&#039; tag and defining the following variables:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note! For Activity modules replace $plugin-&amp;gt; with $module-&amp;gt; in the following example!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* $plugin-&amp;gt;version = 2011051000;&lt;br /&gt;
** Required - the version number of your plugin in the form YYYYMMDDxx, so this example is 10th May 2011 (with 00 indicating this is the first version for that day)&lt;br /&gt;
* $plugin-&amp;gt;requires = 2010112400;&lt;br /&gt;
** Optional - minimum version number of Moodle that this plugin requires (Moodle 1.9 = 2007101509; Moodle 2.0 = 2010112400; Moodle 2.1 = 2011070100; Moodle 2.2 = 2011120100; Moodle 2.3 = 2012062500). See [[Releases]] for a full list.&lt;br /&gt;
* $plugin-&amp;gt;cron = 0;&lt;br /&gt;
** Optional - time interval (in seconds) between calls to the plugin&#039;s &#039;cron&#039; function; set to 0 to disable the cron function calls.&lt;br /&gt;
** Cron support is not yet implemented for all plugins.&lt;br /&gt;
* $plugin-&amp;gt;component = &#039;plugintype_pluginname&#039;;&lt;br /&gt;
** Optional - &#039;&#039;frankenstyle&#039;&#039; plugin name, strongly recommended. It is used for installation and upgrade diagnostics.&lt;br /&gt;
* $plugin-&amp;gt;maturity = MATURITY_STABLE;&lt;br /&gt;
** Optional - how stable the plugin is: MATURITY_ALPHA, MATURITY_BETA, MATURITY_RC, MATURITY_STABLE (Moodle 2.0 and above)&lt;br /&gt;
* $plugin-&amp;gt;release = &#039;2.x (Build: 2011051000)&#039;;&lt;br /&gt;
** Optional - Human-readable version name&lt;br /&gt;
* $plugin-&amp;gt;dependencies = array(&#039;mod_forum&#039; =&amp;gt; ANY_VERSION, &#039;mod_data&#039;  =&amp;gt; 2010020300);  &lt;br /&gt;
** Optional - list of other plugins that are required for this plugin to work (Moodle 2.2 and above)&lt;br /&gt;
** In this example, the plugin requires any version of the forum activity and version &#039;20100020300&#039; (or above) of the database activity&lt;br /&gt;
&lt;br /&gt;
Here is a template to copy and paste:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * TODO&lt;br /&gt;
 *&lt;br /&gt;
 * @package   TODO_FRANKENSTYLE&lt;br /&gt;
 * @copyright TODO&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
$plugin-&amp;gt;version   = TODO;&lt;br /&gt;
$plugin-&amp;gt;requires  = TODO; // See https://docs.moodle.org/dev/Moodle_Versions&lt;br /&gt;
$plugin-&amp;gt;cron      = 0;&lt;br /&gt;
$plugin-&amp;gt;component = &#039;TODO_FRANKENSTYLE&#039;;&lt;br /&gt;
$plugin-&amp;gt;maturity  = MATURITY_STABLE;&lt;br /&gt;
$plugin-&amp;gt;release   = &#039;TODO&#039;;&lt;br /&gt;
&lt;br /&gt;
$plugin-&amp;gt;dependencies = array(&lt;br /&gt;
    &#039;mod_forum&#039; =&amp;gt; ANY_VERSION,&lt;br /&gt;
    &#039;mod_data&#039;  =&amp;gt; TODO&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Moodle versions]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_2.3_release_notes&amp;diff=34310</id>
		<title>Moodle 2.3 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_2.3_release_notes&amp;diff=34310"/>
		<updated>2012-06-26T11:01:14Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: /* Plugin API changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 25th June 2012&lt;br /&gt;
 &lt;br /&gt;
Here is [http://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%222.3%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 2.3].&lt;br /&gt;
 &lt;br /&gt;
Many thanks to [http://moodle.org/dev/contributions.php?version=2.3.x everyone that worked on the new features in this release], including those from [http://moodle.com/hq/team Moodle HQ], [http://www.open.ac.uk/ The Open University], [http://www.netspot.com.au/ NetSpot], [http://www.synergy-learning.com/ Synergy Learning], [http://www.luns.net.uk/ Lancaster University Network Services], [http://catalyst.net.nz/ Catalyst IT], [http://www.cvaconsulting.com/ CV&amp;amp;A Consulting] (funded by [http://www.esade.edu ESADE] and [http://www.il3.ub.edu IL3-UB]) and others.  More details can be found below under each major feature, or look at the list of bugs fixed above.&lt;br /&gt;
&lt;br /&gt;
A special thanks to our incredible &#039;&#039;&#039;&#039;Integration Team&#039;&#039;&#039;&#039; from Moodle HQ who worked tirelessly with all developers to review, test and help finish code for inclusion in Moodle core:&lt;br /&gt;
&lt;br /&gt;
* Eloy Lafuente&lt;br /&gt;
* Sam Hemelryk&lt;br /&gt;
* Dan Poltawski&lt;br /&gt;
* Aparup Bannerjee &lt;br /&gt;
&lt;br /&gt;
Finally, thanks to all our testers both within Moodle HQ and from the whole community, who have contributed to producing our most exciting and stable release yet!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Requirements===&lt;br /&gt;
&lt;br /&gt;
* Minimum browser: Firefox 4, Internet Explorer 8, Safari 5, Google Chrome 11, Opera 9&lt;br /&gt;
* Moodle upgrade:  Moodle 2.2 or later (if upgrading from earlier versions, you must upgrade to 2.2 as a first step)&lt;br /&gt;
* Minimum DB versions: Postgres 8.3, MySQL 5.1.33 (MDL-33984), MSSQL 2005 or Oracle 10.2&lt;br /&gt;
* Minimum PHP version: PHP 5.3.2&lt;br /&gt;
&lt;br /&gt;
===Major new features===&lt;br /&gt;
&lt;br /&gt;
====Files usability====&lt;br /&gt;
&lt;br /&gt;
* MDL-31907 - A nicer-looking file picker with fewer clicks.&lt;br /&gt;
* Images now display as true thumbnails in the file picker and file manager.&lt;br /&gt;
* Other files have pretty icons for most file types.&lt;br /&gt;
* Files view can be easily toggled between icons view or a table view with sizes and dates, or a hierarchical list view.&lt;br /&gt;
* You can now drag and drop files directly from your desktop straight into file areas!&lt;br /&gt;
* File info (eg license information, sizes, dates) can be easily edited and viewed in a popup dialogue.&lt;br /&gt;
* Files can be created as &amp;quot;aliases/shortcuts&amp;quot; of other files.  This allows you to, for example, use a single file in your private files area multiple times in all your courses.  If you update the original file then all the aliases will automatically update!&lt;br /&gt;
* Aliases are easily identifiable in the file manager interface.&lt;br /&gt;
&lt;br /&gt;
Credits to Moodle HQ: Marina Glancy, Barbara Ramiro, Martin Dougiamas, David Mudrak, Dongsheng Cai and others.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| [[File:truthumbnailsiconsview.png|thumb|File picker icon view]]&lt;br /&gt;
| [[File:tableview.png|thumb|File picker table view]]&lt;br /&gt;
| [[File:hierarchicallistview.png|thumb|File picker hierarchical list view]]&lt;br /&gt;
|-&lt;br /&gt;
| [[File:popupdialogue.png|thumb|File info popup dialogue]]&lt;br /&gt;
| [[File:alias.png|thumb|Creating an alias]]&lt;br /&gt;
| [[File:shortcut1.png|thumb|Aliases are easily identifiable]]&lt;br /&gt;
|}&lt;br /&gt;
====Repository improvements====&lt;br /&gt;
&lt;br /&gt;
* MDL-32117 - New [https://docs.moodle.org/23/en/EQUELLA_repository EQUELLA repository] enabling users to make aliases (shortcuts) to EQUELLA files.&lt;br /&gt;
* MDL-28666 - If a repository supports it then it&#039;s possible to make an alias/shortcut to a file in an external repository.  If the file is updated in the repository, then this change is reflected in Moodle.  The file remains under Moodle access control however, and the original URL is not usually revealed. In the 2.3 core release, this is supported by private files, server files, file system, Box.net and EQUELLA repositories.&lt;br /&gt;
* The repository plugin is now able to take over the whole right-hand pane of the file picker and provide it&#039;s own searching/browsing interface.&lt;br /&gt;
* MDL-31675 - Server files repository now available for database, forum and glossary activities.&lt;br /&gt;
&lt;br /&gt;
Credits to Moodle HQ: Dongsheng Cai, Marina Glancy, Martin Dougiamas, Petr Skoda&lt;br /&gt;
&lt;br /&gt;
====Improvements to course pages ====&lt;br /&gt;
&lt;br /&gt;
* MDL-32476 - Courses can now choose to show sections on individual pages&lt;br /&gt;
* MDL-31052 - All AJAX editing on the course pages has been modernised and cleaned up (YUI3).  It&#039;s on by default now too.&lt;br /&gt;
* MDL-31263 - Blocks can be dragged and dropped around the page (again)&lt;br /&gt;
* MDL-30617 - An optional new popup [https://docs.moodle.org/23/en/Course_homepage &amp;quot;Activity chooser&amp;quot;] has been added with full introduction, examples and links about each activity or resource module.&lt;br /&gt;
* MDL-22504 - You can now drag files straight into the course page and they will be added as resources.&lt;br /&gt;
* MDL-31215 - You can edit the name of any activity or resource directly on the course page without entering the settings (works particularly well with drag and drop).&lt;br /&gt;
* MDL-32771 - You can now add/remove sections directly from the [https://docs.moodle.org/23/en/Course_homepage course page].&lt;br /&gt;
&lt;br /&gt;
Credits to: Andrew Nicols and Ruslan Kabalin (LUNS) Davo Smith (Synergy Learning), Dan Poltawski and Martin Dougiamas (Moodle HQ)&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
| [[File:dragandrop.png|thumb|File drag and drop]]&lt;br /&gt;
| [[File:activity chooser.png|thumb|Activity chooser]]&lt;br /&gt;
|}&lt;br /&gt;
====Assignment module====&lt;br /&gt;
&lt;br /&gt;
* MDL-26997 - Complete rewrite of the assignment module from scratch, by [http://www.netspot.com.au/ NetSpot] (Moodle Partner in Australia)&lt;br /&gt;
* Assignment subtypes are no longer needed.  New plugins are possible for &lt;br /&gt;
* Old Assignment module is still installed, and works, but is not necessary &lt;br /&gt;
&lt;br /&gt;
Credits to Netspot: Damyon Wiese, Raymond Wijaya, Minh-Tam Nguyen&lt;br /&gt;
&lt;br /&gt;
* MDL-31731 - New [https://docs.moodle.org/23/en/Marking_guide marking guide] advanced grading method, where a teacher enters a comment per criterion and a mark up to a maximum&lt;br /&gt;
&lt;br /&gt;
Credits to Catalyst IT: Dan Marsden with funding from the Lightwork team at Massey University.&lt;br /&gt;
&lt;br /&gt;
====Book module====&lt;br /&gt;
&lt;br /&gt;
* MDL-32709 - The most popular third-party resource module ever, [https://docs.moodle.org/23/en/Book_module Book] finally joins core.  Welcome!&lt;br /&gt;
&lt;br /&gt;
Credits to Petr Škoda, Moodle HQ&lt;br /&gt;
&lt;br /&gt;
====Quiz module====&lt;br /&gt;
 &lt;br /&gt;
* MDL-3030 - More robust handling of quiz attempts that are not submitted by the deadline.&lt;br /&gt;
* MDL-3054 &amp;amp; MDL-11047 - There is now an option for teacher to force students to answer the quiz questions strictly in order. As part of this, the quiz remembers which page the student was last on, and will take them back there when they resume an attempt.&lt;br /&gt;
&lt;br /&gt;
Credits to Tim Hunt, The Open University and Charles Fulton, Lafayette College&lt;br /&gt;
&lt;br /&gt;
====SCORM module====&lt;br /&gt;
&lt;br /&gt;
* MDL-29745 - New [https://docs.moodle.org/23/en/Using_SCORM SCORM graph report] plugin (credits to Ankit Agarwal, Moodle HQ and Dan Marsden, Catalyst IT)&lt;br /&gt;
* MDL-32937 - You can now drag a SCORM package straight into the course page and it will be added as SCORM activity (credits to Christopher Tombleson and Dan Marsden, Catalyst IT, and Davo Smith, Synergy Learning)&lt;br /&gt;
&lt;br /&gt;
====Workshop module====&lt;br /&gt;
&lt;br /&gt;
* MDL-26099 - [https://docs.moodle.org/23/en/Workshop_settings Option to make the workshop switch to the assessment phase] automatically after the submissions deadline (including automatic allocation of submissions for assessment)&lt;br /&gt;
* MDL-25660 - Workshop submission deadlines are shown in the calendar&lt;br /&gt;
* MDL-27508 - Improved support for pagination and filtering workshop submissions by group&lt;br /&gt;
* MDL-32638 - Workshop supports file browsing via Server files repository (including improved access control when serving submission files)&lt;br /&gt;
&lt;br /&gt;
Credits to David Mudrak, Moodle HQ&lt;br /&gt;
&lt;br /&gt;
====Available update notifications====&lt;br /&gt;
&lt;br /&gt;
*MDL-20438 - Admins are sent [https://docs.moodle.org/23/en/Notifications notification of any updates available] for core code and for any contributed plugins installed on the site (from the [http://moodle.org/plugins plugins directory]). Admins can also check for available updates using buttons on the notifications and plugins overview pages.&lt;br /&gt;
&lt;br /&gt;
Credits to David Mudrak, Moodle HQ&lt;br /&gt;
&lt;br /&gt;
===Other highlights===&lt;br /&gt;
&lt;br /&gt;
====Google Docs and Picasa plugins requirement====&lt;br /&gt;
&lt;br /&gt;
* MDL-29857 - Due to a change in Google&#039;s service, Moodle has switched to a more secure and more user-friendly system for communicating with Google called &#039;OAuth 2.0&#039;. An administrator must register their site with Google, as described in [https://docs.moodle.org/23/en/Google_OAuth_2.0_setup Google OAuth 2.0 setup] in order to obtain a client ID and secret for use in configuring all Google Docs and Picasa plugins (the Google Docs and Picasa repositories and the Google Docs and Picasa portfolios).&lt;br /&gt;
&lt;br /&gt;
Credits to Dan Poltawski, Moodle HQ&lt;br /&gt;
&lt;br /&gt;
====IMS Common Cartridge 1.1 Export====&lt;br /&gt;
&lt;br /&gt;
* MDL-33079 - In Moodle 2.2 we introduced IMS CC import.  Well, now you can also export to that format, via the normal Backup menu.  Just look for the IMS CC checkbox.&lt;br /&gt;
&lt;br /&gt;
====Miscellaneous====&lt;br /&gt;
&lt;br /&gt;
* MDL-31121 - Option in [https://docs.moodle.org/23/en/File_module_settings file resource settings] to display file size and/or type on course page (credits to Sam Marshall, The Open University)&lt;br /&gt;
* MDL-32009 - Admin option for uninstalling messaging outputs and report of messaging output statuses on plugins overview page&lt;br /&gt;
* MDL-29941 - Admin option to enable a [https://docs.moodle.org/23/en/CSS_optimiser CSS optimiser] that analyses and refactors CSS before caching it&lt;br /&gt;
* MDL-24419 - [https://docs.moodle.org/23/en/Conditional_activities_settings Conditional activities setting] enabling teachers to restrict access to a course section using similar logic to Conditional Activities (with thanks to the [http://www.unsw.edu.au/ University of New South Wales] for funding and [http://www.netspot.com.au/ NetSpot] for developing this feature and Sam Marshall at the [http://www.open.ac.uk OU] for integrating it to core) &lt;br /&gt;
* MDL-26901 - Option to add extra fonts to the [https://docs.moodle.org/23/en/Text_editor TinyMCE HTML editor]&lt;br /&gt;
* MDL-31315 - When editing a form, a warning will be displayed if trying to navigate away with content edited&lt;br /&gt;
* MDL-33401 - Managers are now allowed the capability to edit blocks (moodle/block:edit) by default for new installs. This does not affect existing installations.&lt;br /&gt;
* MDL-32005 - New group and groupings ID number setting for matching groups and groupings against external systems (credits to Andrew Nicols, LUNS)&lt;br /&gt;
* MDL-30482 - New [https://docs.moodle.org/23/en/Capabilities/mod/glossary:view view glossary entries capability]&lt;br /&gt;
* MDL-31158 - New [https://docs.moodle.org/23/en/Grade_settings recover grades default setting]&lt;br /&gt;
* MDL-11378 - New [https://docs.moodle.org/23/en/Messaging_settings SMTP security email setting]&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
All security issues that were fixed in 2.2.x and 2.1.x were also fixed in 2.3. &lt;br /&gt;
 &lt;br /&gt;
===For developers: API changes===&lt;br /&gt;
&lt;br /&gt;
Abbreviated descriptions of API changes are always kept up to date in the &amp;quot;upgrade.txt&amp;quot; within each plugin area.  We do this so that the information is always exactly right for the version of Moodle you are using. Changes in this release:&lt;br /&gt;
&lt;br /&gt;
;Blocks: http://git.moodle.org/gw?p=moodle.git;a=blob;f=blocks/upgrade.txt;hb=master&lt;br /&gt;
;Course formats: http://git.moodle.org/gw?p=moodle.git;a=blob;f=course/format/upgrade.txt;hb=master&lt;br /&gt;
;Filters: http://git.moodle.org/gw?p=moodle.git;a=blob;f=filter/upgrade.txt;hb=master&lt;br /&gt;
;Activity modules: http://git.moodle.org/gw?p=moodle.git;a=blob;f=mod/upgrade.txt;hb=master&lt;br /&gt;
;Quiz access rules: http://git.moodle.org/gw?p=moodle.git;a=blob;f=mod/quiz/accessrule/upgrade.txt;hb=master&lt;br /&gt;
;Quiz reports: http://git.moodle.org/gw?p=moodle.git;a=blob;f=mod/quiz/report/upgrade.txt;hb=master&lt;br /&gt;
;Portfolio plugins: http://git.moodle.org/gw?p=moodle.git;a=blob;f=portfolio/upgrade.txt;hb=master&lt;br /&gt;
;Question behaviour plugins: http://git.moodle.org/gw?p=moodle.git;a=blob;f=question/behaviour/upgrade.txt;hb=master&lt;br /&gt;
;Question behaviour plugins: http://git.moodle.org/gw?p=moodle.git;a=blob;f=question/format/upgrade.txt;hb=master&lt;br /&gt;
;Question types: http://git.moodle.org/gw?p=moodle.git;a=blob;f=question/type/upgrade.txt;hb=master&lt;br /&gt;
;Repository plugins: http://git.moodle.org/gw?p=moodle.git;a=blob;f=repository/upgrade.txt;hb=master&lt;br /&gt;
;Themes: http://git.moodle.org/gw?p=moodle.git;a=blob;f=theme/upgrade.txt;hb=master&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Core API changes====&lt;br /&gt;
* MDL-31902 All xxx_get_participants() functions are removed from core&lt;br /&gt;
* As a part of MDL-32471, the signature of send_stored_file() has been [http://git.moodle.org/gw?p=moodle.git;a=commitdiff;h=796495fed29f12e4a81bd406558d8eeffd0e64ac modified]. The last two parameters $filename and $dontdie were replaced with a single array containing additional options for the file serving. The pluginfile callbacks in plugins are supposed to transfer these options from the caller to send_stored_file() - see the note below.&lt;br /&gt;
* MDL-28666 Files API changes, added ability to create file reference using file_storage::create_file_from_reference() method, update file record attributes using stored_file class&lt;br /&gt;
* MDL-28666 Repository API changes, added new APIs repository::get_file_reference(), repository::get_file_by_reference(), repository::get_reference_details(), repository::send_file(), the new APIs make serving files from external repository possible&lt;br /&gt;
* MDL-33446 Make sure that areas in your plugins where you DON&#039;T want content to change have support for file references turned OFF.  Some areas in Moodle core that do not support references are assignment submissions, workshop submissions, forum posts, and quiz essay questions - this is so that students are not able to update files from outside Moodle after any due date&lt;br /&gt;
* AJAX Flags: MDL-32509 and MDL-32908 The $CFG-&amp;gt;enablecourseajax  and $USER-&amp;gt;ajax fields have been removed. The fields was not widely respected and all &#039;advanced javascript&#039; should work in a progressive enhancement and accessible way. A site wide flag still exists but may be phased out in the future.&lt;br /&gt;
&lt;br /&gt;
====Plugin API changes====&lt;br /&gt;
&lt;br /&gt;
* As a part of MDL-32471, the API of the plugin function xyz_pluginfile() has been extended. There is a new array parameter passed to these callbacks containing additional options for the file serving. The array should be re-passed to send_stored_file(). The change is pretty trivial - see [http://git.moodle.org/gw?p=moodle.git;a=commitdiff;h=261cbbacc15ef1732a357d689908c91c15e0617a examples].&lt;br /&gt;
* Activity modules can now declare support for course drag and drop upload [[Implementing_Course_drag_and_drop_upload_support_in_a_module]]&lt;br /&gt;
&lt;br /&gt;
====Webservice changes====&lt;br /&gt;
Few changes could break existing web service clients in 2.3 - untill this version we tried not to break anything. However these changes will make the client&#039;s developer life easier, so we prefered to do them now than later. Please take in consideration these improvements and retest your clients:&lt;br /&gt;
* [https://docs.moodle.org/dev/Errors_handling_in_web_services Error codes and Warnings]&lt;br /&gt;
* All text fields have an additional format field as parameter and return value (MDL-32581)&lt;br /&gt;
* Thanks to the increasing number of contributions, we improved our [https://docs.moodle.org/dev/How_to_contribute_a_web_service_function_to_core contributor web service guide]&lt;br /&gt;
* From 2.3, all web service functions integrated in master will land (when possible) in supported minor versions (e.g. 2.3.1, 2.3.2...).&lt;br /&gt;
* Many [http://tracker.moodle.org/browse/MDL-31253 fixes] and new [http://tracker.moodle.org/browse/MDL-29934 API functions].&lt;br /&gt;
&lt;br /&gt;
====Unit tests====&lt;br /&gt;
&lt;br /&gt;
We have switched completely to using [[PHPUnit]] for all our unit tests now.  All existing simpletests have been rewritten, and new tests have been added.  &lt;br /&gt;
&lt;br /&gt;
We intend to move towards a completely unit-test-driven development methodology (where the tests are written first!) for significant new code, and we also encourage all developers to implement unit tests covering at least the core features of their code.&lt;br /&gt;
&lt;br /&gt;
Moodle HQ run these tests on an automated basis for all new code submitted for integration, as well as on each weekly release.&lt;br /&gt;
&lt;br /&gt;
==== Community hub changes ====&lt;br /&gt;
Some bug fixes and improvements in [http://tracker.moodle.org/browse/MDL-30247  core] and in the [http://tracker.moodle.org/browse/CONTRIB-3348 plugin]. Hub administrators must update their hub to the most recent version regarding CONTRIB-3646. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;==See also==&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/23/en/Category:New_features User documentation of new features in Moodle 2.3]&lt;br /&gt;
* [https://docs.moodle.org/23/en/Upgrading_to_Moodle_2.3 Upgrading to Moodle 2.3] - information for admins who are upgrading from earlier versions&lt;br /&gt;
*[[Moodle 2.2 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 2.3]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 2.3]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Implementing_Course_drag_and_drop_upload_support_in_a_module&amp;diff=34309</id>
		<title>Implementing Course drag and drop upload support in a module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Implementing_Course_drag_and_drop_upload_support_in_a_module&amp;diff=34309"/>
		<updated>2012-06-26T10:59:12Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;When a user drags and drops files, links or text onto a course, any activity module can register to receive this data. Note that only &amp;#039;file&amp;#039; support is enabled by default - text ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;When a user drags and drops files, links or text onto a course, any activity module can register to receive this data. Note that only &#039;file&#039; support is enabled by default - text &amp;amp; URL handling needs to be enabled under the system &#039;experimental&#039; features.&lt;br /&gt;
&lt;br /&gt;
To support drag and drop upload, the module needs to add the following two functions to its lib.php file:&lt;br /&gt;
&lt;br /&gt;
== xx_dndupload_register() ==&lt;br /&gt;
&lt;br /&gt;
This should return an array declaring what types of upload it can handle (and, optionally, any extra types that are not supported as standard).&lt;br /&gt;
&lt;br /&gt;
If the module wants to accept files, then it should return something like this: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
return array(&#039;files&#039; =&amp;gt; array(&lt;br /&gt;
                 array(&#039;extension&#039; =&amp;gt; &#039;doc&#039;, &#039;message&#039; =&amp;gt; get_string(&#039;dosomethingwithdoc&#039;, &#039;mod_xx&#039;)),&lt;br /&gt;
                 array(&#039;extension&#039; =&amp;gt; &#039;pdf&#039;, &#039;message&#039; =&amp;gt; get_string(&#039;dosomethingwithpdf&#039;, &#039;mod_xx&#039;))&lt;br /&gt;
            ));&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code declares that the particular module wants to handle files ending &#039;.doc&#039; or &#039;.pdf&#039; and also gives the text to display to the user if there is a choice of more than one module to handle that particular file type. Note setting the extension to &#039;*&#039; will mean this module could handle any file type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To handle non-file types, the return should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
return array(&#039;types&#039; =&amp;gt; array(&lt;br /&gt;
                 array(&#039;identifier&#039; =&amp;gt; &#039;url&#039;, &#039;message&#039; =&amp;gt; get_string(&#039;dosomethingwithurl&#039;, &#039;mod_xx&#039;)),&lt;br /&gt;
                 array(&#039;identifier&#039; =&amp;gt; &#039;text/html&#039;, &#039;message&#039; =&amp;gt; get_string(&#039;dosomethingwithhtml&#039;, &#039;mod_xx&#039;)),&lt;br /&gt;
                 array(&#039;identifier&#039; =&amp;gt; &#039;text&#039;, &#039;message&#039; =&amp;gt; get_string(&#039;dosomethingwithtext&#039;, &#039;mod_xx&#039;))&lt;br /&gt;
             ));&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This declares that the particular module wants to handle all 3 built-in drop types (url, text/html, text) and gives the message to display in each case, if the user has a choice of more than one module to handle that particular type. Note that you can declare support for both &#039;files&#039; and &#039;types&#039; by including both in the returned array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you need to support the dropping of other types onto the course (in addition to files, text, text/html or url), you can declare the type as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
return array(&#039;addtypes&#039; =&amp;gt; array(&lt;br /&gt;
                 array(&#039;identifier&#039; =&amp;gt; &#039;newtypename&#039;, &#039;datatransfertypes&#039; =&amp;gt; array(&#039;newtype&#039;, &#039;text/newtype&#039;), &lt;br /&gt;
                       &#039;addmessage&#039; =&amp;gt; get_string(&#039;addmessage&#039;, &#039;mod_xx&#039;), &#039;namemessage&#039; =&amp;gt; get_string(&#039;namemessage&#039;, &#039;mod_xx&#039;),&lt;br /&gt;
                       &#039;priority&#039; =&amp;gt; 100)&lt;br /&gt;
             ));&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This declares support for a new type, to be known as &#039;newtypename&#039; (which is the &#039;identifier&#039; you would need to put in the &#039;types&#039; array in the previous section). This should be used whenever the browser declares the clipboard data includes one of the types listed in &#039;datatransfertypes&#039;. Whilst the drag is in progress, the &#039;addmessage&#039; will be displayed in the current course section (e.g. &#039;Add a new page here&#039;). Once the drag is complete, the &#039;namemessage&#039; will be displayed to the user, to get the activity name (e.g. &#039;What do you want to call this page?&#039;). The priority controls the order in which types are chosen (smaller meaning earlier) - this allows, for example, the &#039;url&#039; type to be chosen first even when the data could also be interpreted as &#039;text&#039; type.&lt;br /&gt;
&lt;br /&gt;
== xx_dndupload_handle($uploadinfo) ==&lt;br /&gt;
&lt;br /&gt;
This function receives information about the current upload. It is expected to create a new instance of the module (similarly to how xx_add_instance works) and return the new instance id. If there is a problem, it should return 0 (the coursemodule will then be deleted and the user informed that there was a problem creating the activity).&lt;br /&gt;
&lt;br /&gt;
The data supplied includes:&lt;br /&gt;
* $uploadinfo-&amp;gt;course - the course object that the upload was dropped onto&lt;br /&gt;
* $uploadinfo-&amp;gt;displayname - the name the user gave (or the name of the file, after removing the extension and replacing underscores with spaces)&lt;br /&gt;
* $uploadinfo-&amp;gt;coursemodule - the ID of the coursemodule created to hold this activity&lt;br /&gt;
* $uploadinfo-&amp;gt;type - the type of upload (either &#039;Files&#039;, or one of the &#039;types&#039; identifiers listed above)&lt;br /&gt;
* $uploadinfo-&amp;gt;draftitemid - the ID of the draft area that stores the file the user has uploaded (only for &#039;Files&#039; type - note there will only be a single file in the area, as multi-file uploads are handled as separate AJAX calls)&lt;br /&gt;
* $uploadinfo-&amp;gt;content - the raw content dropped onto the browser (only for non-file uploads)&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
Please take a look at the code for the built-in modules: resource, folder, scorm, url or page for examples of how to use these functions&lt;br /&gt;
&lt;br /&gt;
[[Category:Modules]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Activity_modules&amp;diff=34306</id>
		<title>Activity modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Activity_modules&amp;diff=34306"/>
		<updated>2012-06-26T10:18:00Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Add a mention of course drag and drop upload support&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Activity modules reside in the &#039;&#039;&#039;/mod&#039;&#039;&#039; directory.  They are the oldest type of plugins in Moodle - that&#039;s why they have this overly-generic name and also why they have a few idiosyncrasies and operate slightly differently from all the plugins that came later.&lt;br /&gt;
&lt;br /&gt;
Each module is in a separate subdirectory and consists of a number of &#039;&#039;&#039;&#039;mandatory elements&#039;&#039;&#039;&#039; (see below) plus extra scripts unique to each module.&lt;br /&gt;
&lt;br /&gt;
In the example below we will assume a module called &#039;&#039;&#039;&#039;widget&#039;&#039;&#039;&#039;, that is stored in the &#039;&#039;&#039;&#039;/mod/widget&#039;&#039;&#039;&#039; directory.   All functions and classes should have names starting with &#039;&#039;&#039;widget_&#039;&#039;&#039;&#039; and any constants you define should start with &#039;&#039;&#039;&#039;WIDGET_&#039;&#039;&#039;&#039;.   (Note that activity modules are the only exception from the normal frankenstyle naming rules which would normally have required prefixes like &amp;quot;mod_widget_&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;[[mod_form.php]]&#039;&#039; - a form to set up or update an instance of this module&lt;br /&gt;
* &#039;&#039;[[version.php]]&#039;&#039; - defines some meta-info&lt;br /&gt;
* &#039;&#039;pix/icon.gif&#039;&#039; - a 16x16 icon for the module&lt;br /&gt;
* &#039;&#039;db/install.xml&#039;&#039; - defines the structure of db tables for all database types. Is used during module installation&lt;br /&gt;
* &#039;&#039;[[db/upgrade.php]]&#039;&#039; - defines changes in the structure of db tables. Is used during module upgrade&lt;br /&gt;
* &#039;&#039;[[db/access.php]]&#039;&#039; - defines module capabilities&lt;br /&gt;
* &#039;&#039;[[index.php]]&#039;&#039; - a page to list all instances in a course&lt;br /&gt;
* &#039;&#039;[[view.php]]&#039;&#039; - a page to view a particular instance&lt;br /&gt;
* &#039;&#039;[[lib.php]]&#039;&#039; - all functions intended to be called from OUTSIDE this activity module are here.   Required functions are:&lt;br /&gt;
:* widget_install() - will be called during the installation of the module&lt;br /&gt;
:* widget_add_instance() - code to add a new instance of widget&lt;br /&gt;
:* widget_update_instance() - code to update an existing instance&lt;br /&gt;
:* widget_delete_instance() - code to delete an instance&lt;br /&gt;
:* widget_user_outline() - given an instance, return a summary of a user&#039;s contribution&lt;br /&gt;
:* widget_user_complete() - given an instance, print details of a user&#039;s contribution&lt;br /&gt;
:* widget_get_view_actions() / widget_get_post_actions() - Used by the participation report (course/report/participation/index.php) to classify actions in the logs table.&lt;br /&gt;
:* Other functions available but not required are:&lt;br /&gt;
:** widget_delete_course() - code to clean up anything that would be leftover after all instances are deleted&lt;br /&gt;
:** widget_process_options() - code to pre-process the form data from module settings&lt;br /&gt;
:** [[Implementing Reset course functionality in a module|widget_reset_course_form() and widget_delete_userdata()]] - used to implement [[Reset course]] feature.&lt;br /&gt;
:** [[Implementing Course drag and drop upload support in a module|widget_dndupload_register() and widget_dndupload_handle()]] - used to support Course drag and drop upload.&lt;br /&gt;
* &#039;&#039;backuplib.php&#039;&#039; and &#039;&#039;restorelib.php&#039;&#039; (optional)&lt;br /&gt;
* &#039;&#039;settings.php&#039;&#039; or &#039;&#039;settingstree.php&#039;&#039; - (optional) a definition of an admin settings page for this module. mod/assignment/settings.php is a good simple example. mod/quiz/settingstree.php is a more complex example.&lt;br /&gt;
* &#039;&#039;defaults.php&#039;&#039; - lets you easily define default values for your configuration variables. It is included by upgrade_activity_modules in lib/adminlib.php. It should define an array $defaults. These values are then loaded into the config table. Alternatively, if you set $defaults[&#039;_use_config_plugins&#039;] to true, the values are instead loaded into the config_plugins table, which is better practice. See mod/quiz/defaults.php for an example. (This apparently only works with moodle 2.x branch.)&lt;br /&gt;
* &#039;&#039;lang/en/widget.php&#039;&#039; -  Lastly, each module will have some language files that contain strings for that module, especially:&lt;br /&gt;
:* $string[&#039;pluginname&#039;] = &#039;Widget&#039;;&lt;br /&gt;
&lt;br /&gt;
=== IMPORTANT: ===&lt;br /&gt;
* When creating a new module, the new name of the module must not contain numbers or other special characters!&lt;br /&gt;
&lt;br /&gt;
* You need a &#039;&#039;data base table&#039;&#039; with the same name as your module. This table must have at least three fields: &lt;br /&gt;
*# id &lt;br /&gt;
*# course &lt;br /&gt;
*# name&lt;br /&gt;
&lt;br /&gt;
* You should also make sure that your activity module provides appropriate support for groups and meta-courses. &lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Moodle 2.x activity module template [https://github.com/moodlehq/moodle-mod_newmodule https://github.com/moodlehq/moodle-mod_newmodule] for developing new modules.&lt;br /&gt;
* [[Blocks]]&lt;br /&gt;
* [[Backup]]&lt;br /&gt;
* Tracker issue [http://tracker.moodle.org/browse/CONTRIB-52 CONTRIB-52 Improvements to make NEWMODULE really useful] - including download link for new module template supporting roles, formslib etc. (unfinished) &lt;br /&gt;
* http://download.moodle.org/plugins16/mod/NEWMODULE.zip - new module template for versions of Moodle prior to 1.7. Please follow the README instructions inside the zip.&lt;br /&gt;
* [[NEWMODULE_Documentation]]&lt;br /&gt;
&lt;br /&gt;
Using Moodle forum discussions:&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=66165 A new resource type: where do I put the language strings?]&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=65986 New Module Template Code for Moodle 1.7]&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=90154 LEGACY roles and capabilities]&lt;br /&gt;
&lt;br /&gt;
[[Category:Modules]]&lt;br /&gt;
[[Category:Modules]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Plugin_validation&amp;diff=34224</id>
		<title>Plugin validation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Plugin_validation&amp;diff=34224"/>
		<updated>2012-06-18T18:46:29Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Clarified the timescales involved in manual checking.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Before a plugin can be made available via the [http://moodle.org/plugins/ Moodle Plugins directory] it has to pass both an automatic and a manual validation process. The automatic checks are repeated for each new version of the plugin that is added, however the [http://moodle.org/mod/forum/discuss.php?d=192083#p837517 manual checks are only done for the initial release]. The aim is to complete manual checks within 48 hours of first submission, but it can sometimes take longer than that, so please be patient.&lt;br /&gt;
=Automatic validation=&lt;br /&gt;
&lt;br /&gt;
==General rules for all plugin types==&lt;br /&gt;
* Plugin name with [[Frankenstyle]] prefix must be unique in moodle.org/plugins. If there is another plugin with the same name you must either add new versions to this plugin (if it is yours) or rename your plugin if the names are accidentally the same. First in first served.&lt;br /&gt;
* The plugin must be uploaded as a single zip file&lt;br /&gt;
* The zip file must contain a single subfolder, named after your plugin (although the validator can also automatically rename subfolders generated by repos such as GitHub, which appear in the form &#039;username-moodle-pluginname-branchname&#039;)&lt;br /&gt;
* The subfolder must be laid out in such a way that the uploaded file could be unzipped directly into the top-level folder for that plugin type (e.g. an activity plugin called &#039;myplugin&#039; should install correctly when unzipped in the Moodle /mod folder, creating a subfolder /mod/myplugin with all the standard files within it).&lt;br /&gt;
* The subfolder must contain a file called [[version.php]] (follow the link for more details about what should be contained within that file). See exceptions below.&lt;br /&gt;
* Language file must be present in lang/en/FULLNAME.php (for Moodle 2.0+) or lang/en_utf8/FULLNAME.php (for Moodle 1.9). FULLNAME is the plugin name with frankenstyle prefix. See exceptions below.&lt;br /&gt;
* Language file must declare either $string[&#039;modulename&#039;] (for activity modules) or $string[&#039;filtername&#039;] (for Filters) or $string[&#039;pluginname&#039;] (for all other plugin types). See exceptions below.&lt;br /&gt;
* The names of all database tables should start with the full &#039;frankenstyle&#039; plugin name. For example block_myblock, or auth_paypal. See exceptions below.&lt;br /&gt;
* (Recommended) the subfolder should contain a file called README.txt (the validator can automatically rename other extensions to .txt) with details about the current release of the plugin.&lt;br /&gt;
&lt;br /&gt;
==Exceptions==&lt;br /&gt;
* version.php is NOT required (but it is always recommended) for the following plugin types:&lt;br /&gt;
** Themes&lt;br /&gt;
** Course formats&lt;br /&gt;
** Blocks for Moodle 1.9&lt;br /&gt;
** Auth for Moodle 1.9&lt;br /&gt;
* language file is not required for plugins for Moodle 1.9 that are not activity modules&lt;br /&gt;
* $string[&#039;pluginname&#039;] is not required for plugins for Moodle 1.9 that are not activity modules&lt;br /&gt;
* Question types for Moodle versions &amp;lt;= 2.1 instead of $string[&#039;pluginname&#039;] should declare $string[NAME] (where NAME is the name of the plugin without frankenstyle prefix). Starting from 2.2 this was fixed and $string[&#039;pluginname&#039;] shall be used.&lt;br /&gt;
* database tables are allowed to skip mod_ prefix for activity modules&lt;br /&gt;
* database tables are allowed to have question_ prefix instead of qtype_ for Question types. This is for historical reasons, all newly developed plugins are encouraged to have qtype_ prefix.&lt;br /&gt;
&lt;br /&gt;
==Additional checks for activity modules==&lt;br /&gt;
* $module-&amp;gt;version defined in version.php&lt;br /&gt;
* $module-&amp;gt;requires defined in version.php&lt;br /&gt;
* file lib.php exists&lt;br /&gt;
* file lib.php contains “function xxxx_add_instance”&lt;br /&gt;
* file lib.php contains “function xxxx_update_instance”&lt;br /&gt;
* file view.php exists&lt;br /&gt;
* file index.php exists&lt;br /&gt;
* db/install.xml exists&lt;br /&gt;
* db/upgrade.php exists&lt;br /&gt;
* db/access.php exists&lt;br /&gt;
&lt;br /&gt;
==Checks for particular plugin types==&lt;br /&gt;
* Themes: file config.php exists&lt;br /&gt;
* Blocks: file block_xxxx.php exists&lt;br /&gt;
* Auth: file auth.php exists&lt;br /&gt;
* Course formats: file format.php exists&lt;br /&gt;
&lt;br /&gt;
=Manual checks=&lt;br /&gt;
Before the plugin is publicly viewable a trusted reviewer will look through the code to make sure it is a valid plugin. Currently, these checks are completed by Anthony Borrow on a volunteer basis, so please bear with him if this sometimes takes a little longer than you expect. These checks include:&lt;br /&gt;
* The plugin installs cleanly&lt;br /&gt;
* It does not contain any obviously harmful code&lt;br /&gt;
* It is not a spam entry&lt;br /&gt;
* It is not a duplicate of an already uploaded plugin&lt;br /&gt;
&lt;br /&gt;
=Frequently asked questions=&lt;br /&gt;
===Q: My code contains several components, why can&#039;t I distribute it as a single package?===&lt;br /&gt;
A: Moodle architecture supposes that plugins are installed independently. However you can contact the plugins database moderator and ask to add your plugins to the SET. &lt;br /&gt;
For Moodle 2.2 and above you can also specify in your version.php that one plugin depends on another.&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=32627</id>
		<title>Course module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=32627"/>
		<updated>2012-03-02T08:00:09Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: Created page with &amp;quot;==Summary== A course module (often abbreviated &amp;#039;cm&amp;#039;) represents each of the activities and resources found in a course. It contains information about which course and section the...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Summary==&lt;br /&gt;
A course module (often abbreviated &#039;cm&#039;) represents each of the activities and resources found in a course. It contains information about which course and section the activity / resource is displayed on, as well as details about the visibility, group and completion status of the activity.&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The data for the course module is stored in the database table &#039;mdl_course_modules&#039; (the &#039;mdl_&#039; part will be different if you have chosen a non-default prefix for your database tables). This fields in this table link it to a number of other tables in the database. The &#039;course&#039; field links to the &#039;mdl_course&#039; table, which contains everything you need to know about a course. The &#039;module&#039; table links to the &#039;mdl_modules&#039; table, which gives information about the type of the module (e.g. &#039;quiz&#039;, &#039;resource&#039;) as well as its current version number. After looking up the type of the module, the rest of the details about this module can be found by looking up the &#039;instance&#039; value (from the &#039;mdl_course_modules&#039; table) in the &#039;mdl_{type}&#039; table. Here you can find the name and introductory paragraph for the activity / resource, as well as information that is specific to the type of activity being looked at.&lt;br /&gt;
&lt;br /&gt;
You can quickly gather all of this information, by using the &#039;get_fast_modinfo($course)&#039; function. The easiest way to understand the data returned is to use the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $courseid));&lt;br /&gt;
$info = get_fast_modinfo($course);&lt;br /&gt;
print_object($info);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
The cmid (course module id) is used widely throughout Moodle to identify a specific activity / resource. Some of the most important uses are:&lt;br /&gt;
* When linking to a modules &#039;view.php&#039; script, it is passed as the &#039;id&#039; parameter&lt;br /&gt;
* To get the &#039;context&#039; for the module (used when checking user capabilities or linking files to an activity), via the function call &#039;context_module::instance($cmid)&#039; (before Moodle 2.2 this was &#039;get_context_instance(CONTEXT_MODULE, $cmid)&#039;)&lt;br /&gt;
* Every log entry in &#039;mdl_log&#039; that relates to a specific activity has the &#039;cmid&#039; field set&lt;br /&gt;
&lt;br /&gt;
==More documentation==&lt;br /&gt;
* [[Module visibility and display]]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/course_modinfo.html course_modinfo PHPdocs]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/cm_info.html cminfo PHPdocs]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Course_drag_and_drop_upload&amp;diff=31601</id>
		<title>Talk:Course drag and drop upload</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Course_drag_and_drop_upload&amp;diff=31601"/>
		<updated>2012-01-19T16:34:38Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Note: i&#039;m a little out of touch with the mod/ api, so this may not make mod-type sense.&lt;br /&gt;
&lt;br /&gt;
I think I agree with the basic principle of the design, but rather than &#039;[modname]_dndupload_register&#039; which receives dndupload_handler object, I would go for something of something a bit like the repository API with something like a static &#039;[modname]_supports_dndupload&#039; function which returns which types it supports.&lt;br /&gt;
&lt;br /&gt;
I&#039;m not clear on what can be done with non-file types of drag/drop. Can you give some examples of this? --[[User:Dan Poltawski|Dan Poltawski]] 00:21, 20 January 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
If you want to see what non file types can do, try installing my block. Basically, dragging a URL  (from the address bar or from a page) can create a link resource, dragging a selected block of text can create a page resource ... Maybe other people can come up with further examples--[[User:David Smith 2|David Smith 2]] 00:34, 20 January 2012 (WST)&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_drag_and_drop_upload&amp;diff=31546</id>
		<title>Course drag and drop upload</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_drag_and_drop_upload&amp;diff=31546"/>
		<updated>2012-01-17T18:28:17Z</updated>

		<summary type="html">&lt;p&gt;Davosmith: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposed design for adding Drag and Drop upload to course pages, in a similar way (from the user&#039;s perspective) to the [http://moodle.org/plugins/view.php?plugin=block_dndupload Drag and Drop upload block].&lt;br /&gt;
&lt;br /&gt;
==Goals==&lt;br /&gt;
&lt;br /&gt;
* Allow users, with appropriate editing capabilities, to directly drag files (and links / blocks of text / other data types?) onto a course page and have them appear in the course as appropriate resource / activity types&lt;br /&gt;
** There should be as little &#039;friction&#039; as possible to getting files uploaded - sensible defaults should be automatically applied as much as possible&lt;br /&gt;
* Allow different modules to register as handlers of certain file types (based on the file extension) and/or data types (for when a link or some text is dragged &amp;amp; dropped from another application/browser window)&lt;br /&gt;
** If there are multiple handlers for any given file/data type (e.g. a &#039;zip&#039; file could be file resource, be unzipped to create a folder resource or be treated as a SCORM package), then the user should be presented with a list of ways of treating the file and be asked to choose one.&lt;br /&gt;
** Default handlers should be included in appropriate core modules (e.g. &#039;file resource&#039; should handle all file types, &#039;page resource&#039; should handle dropped text/html, &#039;link resource&#039; should handle dropped URLs)&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
A class called dndupload_handler will handle the registration of all the different modules with the file/data types that they handle. When an instance of this class is created, it will search for the &#039;lib.php&#039; file in each subdirectory of &#039;/mod&#039; and then look for a function &#039;[modname]_dndupload_register&#039;. If found, this function will be called and the dndupload_handler object will be passed in as a parameter. This will allow the modules to register the following information:&lt;br /&gt;
* For files:&lt;br /&gt;
** the extension (&#039;*&#039; to handle all extensions)&lt;br /&gt;
** the name of the module to handle this type&lt;br /&gt;
** the message to display to users if there is a choice of modules to handle a particular file&lt;br /&gt;
* For data types, there are two stages:&lt;br /&gt;
** Register the type:&lt;br /&gt;
*** an identifier to know it by&lt;br /&gt;
*** an array of mime types that it maps to (e.g. &#039;url&#039; data type can be declared as &#039;url&#039;, &#039;text/uri-list&#039; depending on browser implementations)&lt;br /&gt;
*** the helper text to display when dragging the type over the course (e.g. &#039;add a link here&#039;)&lt;br /&gt;
*** the text to display when asking the user for a name for the dropped object (e.g. &#039;what do you want to call this link?&#039;) - needed as, unlike files, dragged urls/text blocks do not have an inherent name&lt;br /&gt;
*** a priority (so that &#039;url&#039; can take priority over &#039;text/html&#039; and &#039;text/plain&#039;, as often dropped items provide fallback data types)&lt;br /&gt;
*** Note some default types - url, text/html, text - will be registered by default within the library code&lt;br /&gt;
** Register a type handler:&lt;br /&gt;
*** the identifier of the type&lt;br /&gt;
*** the module to handle this type&lt;br /&gt;
*** the message to display to the user if there is a choice of modules to handle this type&lt;br /&gt;
&lt;br /&gt;
The details about the different types that can be handled will need to be passed onto the initialisation code for the drag and drop javascript code on the page.&lt;br /&gt;
&lt;br /&gt;
The drag and drop code on the page will do the following (most of these are already implemented in the drag and drop upload block):&lt;br /&gt;
# Add the necessary dragenter, dragleave, dragover and drop handlers to each course section&lt;br /&gt;
# When a drag event is detected for a course section, examine the attached data types and, if it is a recognised type (e.g. &#039;File&#039;, &#039;text/plain&#039;), display an appropriate message within the course section (e.g. &#039;Add file(s) here&#039;)&lt;br /&gt;
# When a drop event is detected, check to see how many handlers are registered for that type (based on the data handed in during initialisation), if none - do nothing, if 1 then fire off an AJAX message to the server with the data and the name of the registered module, if more than 1 handler, then present the user with a YUI dialog with a list of ways to handle the type (using the string registered with the handler, above)&lt;br /&gt;
## For non-file types, there will need to be an intermediate step where a YUI dialog is shown to ask the user what to call the resource - where there is also choice of handlers, the two dialogs should be integrated together (e.g. What do you want to call this link? _________ Do you want to create a: [ ] Link to webpage [ ] Link to LTI provider)&lt;br /&gt;
# Show a suitable placeholder (the name of the item you are creating) &amp;amp; progress bar / spinner as the file/data is sent to the server&lt;br /&gt;
# Replace the placeholder with the name of the item as returned by the server, linked to the newly created module instance, with the standard edit tools initialised beside it&lt;br /&gt;
&lt;br /&gt;
On the server side, the following steps will take place:&lt;br /&gt;
# When the AJAX data is received, do the standard checks (e.g. user permissions, sesskey checks, etc)&lt;br /&gt;
# Check whether the data is a file or another data type&lt;br /&gt;
## For files create a draft files area, note the id of the area and use the &#039;upload&#039; repository to add the file to this area&lt;br /&gt;
## For other data types, just store the data in a variable&lt;br /&gt;
# Double-check that the module named in the AJAX data is a registered handler for the type of data in the call&lt;br /&gt;
# Create a course module instance for the chosen module (just as if the user had saved the &#039;add new X module form&#039;), in the course/section detailed in the AJAX data&lt;br /&gt;
# Load the lib.php file for the module and call the function [modname]_dndupload_handle, passing in the appropriate data from the browser:&lt;br /&gt;
## The draft area id / data (depending on whether it is a file or some other data type)&lt;br /&gt;
## The display name (taken from the file name)&lt;br /&gt;
## The type (e.g. &#039;file&#039;, &#039;text/html&#039;, &#039;url&#039;)&lt;br /&gt;
# The module should then handle all its internal initialisation (equivalent to [modname]_add_instance - but with most values using defaults, instead of getting data from the &#039;mod_edit.php&#039; form)&lt;br /&gt;
# Return the necessary data to the browser - the cleaned module name, the icon, the &#039;view&#039; URL to link to and the standard editing tools (which can then be overwritten by the AJAX tools on the client side)&lt;br /&gt;
&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Davosmith</name></author>
	</entry>
</feed>