<?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=Ddelrio1986</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=Ddelrio1986"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Ddelrio1986"/>
	<updated>2026-04-14T04:36:29Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz_reports&amp;diff=53887</id>
		<title>Quiz reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz_reports&amp;diff=53887"/>
		<updated>2018-03-23T13:46:40Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: /* The attempts report classes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}&lt;br /&gt;
&lt;br /&gt;
Quiz report sub-plugins can not only be used to display custom reports on the quiz data, but can also be used to plugin other functionality into the quiz module.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Theses sub-plugins have frankenstyle prefix &amp;lt;tt&amp;gt;quiz_&amp;lt;/tt&amp;gt;, and live inside &amp;lt;tt&amp;gt;mod/quiz/report&amp;lt;/tt&amp;gt;. (The prefix was a historical mistake. It would have been much better to use &amp;lt;tt&amp;gt;quizreport_&amp;lt;/tt&amp;gt;, but it is too late to change now.)&lt;br /&gt;
&lt;br /&gt;
A quiz report plugins just needs to implement one class&lt;br /&gt;
 class quiz_&#039;&#039;name&#039;&#039;_report extends quiz_default_report {&lt;br /&gt;
     public function display($cm, $course, $quiz) {&lt;br /&gt;
         // Generate and display the report, or&lt;br /&gt;
         // other functionality.&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The base class is defined in &amp;lt;tt&amp;gt;mod/quiz/report/default.php&amp;lt;/tt&amp;gt; and you just need to implement the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. This gets called from &amp;lt;tt&amp;gt;mod/quiz/report.php&amp;lt;/tt&amp;gt; after some basic set-up has been done.&lt;br /&gt;
&lt;br /&gt;
==What files make up a quiz report==&lt;br /&gt;
&lt;br /&gt;
 mod/quiz/report/&#039;&#039;name&#039;&#039;/&lt;br /&gt;
     report.php            - Contains the implementation of the quiz_&#039;&#039;name&#039;&#039;_report class.&lt;br /&gt;
     version.php           - Normal Moodle plugin version.php file.&lt;br /&gt;
     lang/en/quiz_&#039;&#039;name&#039;&#039;.php - Language strings for your plugin.&lt;br /&gt;
     db/*                  - lets you define db tables, capabilities, etc.&lt;br /&gt;
     simpletest/*          - Unit tests.&lt;br /&gt;
&lt;br /&gt;
* It is possible to make a working plugin with only the first three of these.&lt;br /&gt;
* The only lang strings you need to define are &amp;lt;tt&amp;gt;pluginname&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;report&#039;&#039;name&#039;&#039;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&#039;&#039;name&#039;&#039;report&amp;lt;/tt&amp;gt;. (This should probably be simplified in the future.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==When a user view the report==&lt;br /&gt;
&lt;br /&gt;
The will go to a URL like &amp;lt;tt&amp;gt;http://.../mod/quiz/report.php?id=&#039;&#039;cmid&#039;&#039;&amp;amp;mode=&#039;&#039;name&#039;&#039;&amp;lt;/tt&amp;gt;. There may also be additional parameters in the URL if your report contains several internal pages with links between them. The statistics and grading reports are good examples of this.&lt;br /&gt;
&lt;br /&gt;
This leads to a call to the &amp;lt;tt&amp;gt;quiz_&#039;&#039;name&#039;&#039;_report::display($quiz, $cm, $course)&amp;lt;/tt&amp;gt; method. You can put whatever code you like in there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The attempts report classes==&lt;br /&gt;
&lt;br /&gt;
There are some useful helper classes in &amp;lt;tt&amp;gt;mod/quiz/report/attemptsreport.php&amp;lt;/tt&amp;gt;. This is basically the common functionality that is used by both the &amp;lt;tt&amp;gt;overview&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;responses&amp;lt;/tt&amp;gt; reports. If you want to make a similar report (with one row for each quiz attempt) you should probably build on these classes.&lt;br /&gt;
&lt;br /&gt;
There are also useful helper functions in &amp;lt;tt&amp;gt;mod/quiz/report/reportlib.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* Most quiz reports use [[lib/tablelib.php]].&lt;br /&gt;
* [http://git.moodle.org/gw?p=moodle.git;a=tree;f=mod/quiz/report;h=b748acaba34655e2efe659475dec3e301541dec1;hb=HEAD The standard quiz reports code in git].&lt;br /&gt;
* [http://moodle.org/plugins/browse.php?list=category&amp;amp;id=13 Contributed quiz reports].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Overriding_a_renderer&amp;diff=53361</id>
		<title>Overriding a renderer</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Overriding_a_renderer&amp;diff=53361"/>
		<updated>2017-11-16T21:22:22Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}&lt;br /&gt;
This document explains renderers and how to override a renderer within a theme in order to achieve a unique look. It assumes you have a grounding in PHP and have read [[Themes]].&lt;br /&gt;
&lt;br /&gt;
==An overview of renderers==&lt;br /&gt;
&lt;br /&gt;
A renderer is a class that handles all of the output for a component of Moodle. It should contain no logic other than what is required to generate the display, and should be compartmentalised into functional chunks, each of which should be responsible for producing a widget or control used within the component. This output will vary depending on what the component is, for example the forum will have a method for displaying a forum post, displaying a thread (which most likely calls the forum post method), and displaying a search form. &lt;br /&gt;
&lt;br /&gt;
These renderers are used as much as possible in Moodle and code is constantly being converted. As Moodle progresses, more of the code should be utilising renderers.&lt;br /&gt;
&lt;br /&gt;
As well as the component renderers there is a core renderer, which is responsible for producing the display for many general things within Moodle, for example tables, action icons, and block regions.&lt;br /&gt;
&lt;br /&gt;
Why use these renderers? They help developers separate the logic and the display when writing code and for theme designers they allow a means by which to take total control of the HTML that Moodle produces.&lt;br /&gt;
&lt;br /&gt;
How do you do that you ask? By overriding them!&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
We will create a test theme that extends the standard theme and does nothing other than override renderers.&lt;br /&gt;
&lt;br /&gt;
1. Open your Moodle installation&#039;s theme directory and within it create a new directory called &#039;&#039;&#039;&#039;&#039;overridetest&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
Within the newly created overridetest directory create a config.php file and add the following PHP to it:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$THEME-&amp;gt;name = &#039;overridetest&#039;;&lt;br /&gt;
$THEME-&amp;gt;parents = array(&#039;standard&#039;, &#039;base&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This tells Moodle that our theme is called overridetest and that it extends both the base and standard themes.&lt;br /&gt;
&lt;br /&gt;
2. The next step is to tell the theme that we want to override renderers. This is simple - we just tell Moodle which render factory we want our theme to use.&lt;br /&gt;
&lt;br /&gt;
A render factory is a class that Moodle will use to find renderers. It is required by Moodle because renderers can exist in several locations within Moodle. These factories are what allow us to override only the renderers we want to rather than having to override them all.&lt;br /&gt;
&lt;br /&gt;
3. To the bottom of the config.php add the following line:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line tells Moodle that for this theme we want to use the &#039;&#039;&#039;theme_overridden_renderer_factory&#039;&#039;&#039;, a special class tells Moodle to look for renderers first within the theme and then in all of the other default locations.&lt;br /&gt;
&lt;br /&gt;
== Templates ==&lt;br /&gt;
&lt;br /&gt;
As of Moodle 2.9 it is preferable to use [[Templates]] rather than generating HTML from php with html_writer.&lt;br /&gt;
&lt;br /&gt;
==All about html_writer (Moodle 2.8 and older) ==&lt;br /&gt;
&lt;br /&gt;
The html_writer class is used quite a bit and so it&#039;s important to understand what it is actually doing.&lt;br /&gt;
&lt;br /&gt;
While you could write all of your HTML manually within a renderer method, it is encouraged to use the html_writer where possible to keep all renderer code similar and easily readable.&lt;br /&gt;
&lt;br /&gt;
The following examples will introduce you to the html_writer, what some of it&#039;s core methods are, and what they produce.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;html_writer::start_tag&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is used to produce an opening tag and takes two arguments - the first the tag to open and the second is the attributes to give the tag. The attributes are an array of key value pairs where the key is the attribute and the value is the value. Things such as class, id, and type are attributes that can be specified in this way.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php echo html_writer::start_tag(&#039;div&#039;, array(&#039;class&#039;=&amp;gt;&#039;blah&#039;)); ?&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;blah&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php echo html_writer::start_tag(&#039;table&#039;, array(&#039;class&#039;=&amp;gt;&#039;generaltable&#039;, &#039;id&#039;=&amp;gt;&#039;mytable&#039;)); ?&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;generaltable&amp;quot; id=&amp;quot;mytable&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;html_writer::end_tag&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is used to simply produce a closing tag for a tag that has been opened by html_writer::start_tag.&lt;br /&gt;
&lt;br /&gt;
It takes just one argument the tag to close.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php echo html_writer::end_tag(&#039;div&#039;); ?&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;?php echo html_writer::end_tag(&#039;table&#039;); ?&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;html_writer::tag&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method takes three arguments and is the combination of start_tag and end_tag plus the inclusion of content.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php echo html_writer::tag(&#039;div&#039;, &#039;I am some content to go into the string&#039;, array(&#039;class&#039;=&amp;gt;&#039;blah&#039;)); ?&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;blah&amp;quot;&amp;gt;I am some content to go into the string&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;html_writer::empty_tag&#039;&#039;&#039;&lt;br /&gt;
The final method empty_tag is used to create a self closing tag. This is useful in situations such as producing image tags, or input fields.&lt;br /&gt;
It takes two arguments -  tag and attributes, the same as start_tag.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php echo html_writer::empty_tag(&#039;img&#039;, array(&#039;src&#039;=&amp;gt;&#039;myimage.png&#039;, &#039;alt&#039;=&amp;gt;&#039;This is my image&#039;)); ?&amp;gt;&lt;br /&gt;
&amp;lt;img src=&amp;quot;myimage.png&amp;quot; alt=&amp;quot;This is my image&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php echo html_writer::empty_tag(&#039;input&#039;, array(&#039;type&#039;=&amp;gt;&#039;text&#039;, &#039;name&#039;=&amp;gt;&#039;afield&#039;, &#039;value&#039;=&amp;gt;&#039;This is a field&#039;)); ?&amp;gt;&lt;br /&gt;
&amp;lt;input type=&amp;quot;input&amp;quot; name=&amp;quot;afield&amp;quot; value=&amp;quot;This is a field&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Our first renderer==&lt;br /&gt;
&lt;br /&gt;
A note about autoloading and namespaces. Moodle 2.8 introduced support for autoloading for renderers. The examples in this page will work on older versions of Moodle, but the autoloaded alternatives are listed in notes for each section.&lt;br /&gt;
&lt;br /&gt;
1. Create a file &#039;&#039;&#039;renderers.php&#039;&#039;&#039; within the root of the theme&#039;s directory. (This could also be renamed &amp;quot;classes/core_renderer.php to use auto-loading).&lt;br /&gt;
&lt;br /&gt;
The first renderer that we will override is the core renderer for Moodle.&lt;br /&gt;
&lt;br /&gt;
2. Within your renderers.php add the following:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we have added is the class definition for our first renderer. Note:&lt;br /&gt;
&lt;br /&gt;
* The name of the renderer is VERY important it is made up of three sections joined by underscores:&lt;br /&gt;
: &#039;&#039;&#039;&#039;&#039;theme&#039;&#039;&#039;&#039;&#039; : This will always be the same when overriding renderers from the theme.&lt;br /&gt;
: &#039;&#039;&#039;&#039;&#039;overridetest&#039;&#039;&#039;&#039;&#039; : This is of course the name of our theme, and should be the name of the theme the renderer is being overridden from.&lt;br /&gt;
: &#039;&#039;&#039;&#039;&#039;core_renderer&#039;&#039;&#039;&#039;&#039; : This is the renderer that we are overriding.&lt;br /&gt;
* The renderer should always extend the renderer it is overriding. This ensures we don&#039;t need to override every method the renderer offers.&lt;br /&gt;
&lt;br /&gt;
With our renderer class defined it&#039;s now time to override our first display method.&lt;br /&gt;
&lt;br /&gt;
In this case you we will override the &#039;&#039;&#039;&#039;&#039;heading()&#039;&#039;&#039;&#039;&#039; method that the core renderer has. This method is used to display a simple header in the page consisting of an h* tag (h2, h3, etc) and the heading itself.&lt;br /&gt;
&lt;br /&gt;
The existing code for the function is as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Outputs a heading&lt;br /&gt;
 * @param string $text The text of the heading&lt;br /&gt;
 * @param int $level The level of importance of the heading. Defaulting to 2&lt;br /&gt;
 * @param string $classes A space-separated list of CSS classes&lt;br /&gt;
 * @param string $id An optional ID&lt;br /&gt;
 * @return string the HTML to output.&lt;br /&gt;
 */&lt;br /&gt;
public function heading($text, $level = 2, $classes = &#039;main&#039;, $id = null) {&lt;br /&gt;
    $level = (integer) $level;&lt;br /&gt;
    if ($level &amp;lt; 1 or $level &amp;gt; 6) {&lt;br /&gt;
        throw new coding_exception(&#039;Heading level must be an integer between 1 and 6.&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    return html_writer::tag(&#039;h&#039; . $level, $text, array(&#039;id&#039; =&amp;gt; $id, &#039;class&#039; =&amp;gt; renderer_base::prepare_classes($classes)));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Pretty simple really, it takes four standard arguments, and outputs a h* tag.&lt;br /&gt;
&lt;br /&gt;
There are several important things to take away from this very simple bit of code:&lt;br /&gt;
* The first three lines are to check that $level is an integer between 1 and 6, this is because that integer gets written to the tag.&lt;br /&gt;
* The final line creates a h* tag with the arguments and returns it as a string.&lt;br /&gt;
* The output is returned rather than being echoed to the page. &#039;&#039;&#039;ALL&#039;&#039;&#039; renderer methods must do this.&lt;br /&gt;
* The html_writer class is used to generate the output rather than creating the string within the function. This is highly recommended for all renderer methods.&lt;br /&gt;
&lt;br /&gt;
3. Let&#039;s override this method within our themes renderer. Within our method we will aim to wrap the h* tag in a div with a class name we choose and then add an image right before the h* tag is printed.&lt;br /&gt;
&lt;br /&gt;
The following code does exactly this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function heading($text, $level = 2, $classes = &#039;main&#039;, $id = null) {&lt;br /&gt;
    $content  = html_writer::start_tag(&#039;div&#039;, array(&#039;class&#039;=&amp;gt;&#039;headingcontainer&#039;));&lt;br /&gt;
    $content .= html_writer::empty_tag(&#039;img&#039;, array(&#039;src&#039;=&amp;gt;$this-&amp;gt;pix_url(&#039;headingpic&#039;, &#039;theme&#039;), &#039;alt&#039;=&amp;gt;&#039;&#039;, &#039;class&#039;=&amp;gt;&#039;headingimage&#039;));&lt;br /&gt;
    $content .= parent::heading($text, $level, $classes, $id);&lt;br /&gt;
    $content .= html_writer::end_tag(&#039;div&#039;);&lt;br /&gt;
    return $content;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Looking at the code line by line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content  = html_writer::start_tag(&#039;div&#039;, array(&#039;class&#039;=&amp;gt;&#039;headingcontainer&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Here we are opening a div and giving it a class of &#039;&#039;headingcontainer&#039;&#039; using the html_writer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content .= html_writer::empty_tag(&#039;img&#039;, array(&#039;src&#039;=&amp;gt;$this-&amp;gt;pix_url(&#039;headingpic&#039;, &#039;theme&#039;), &#039;alt&#039;=&amp;gt;&#039;&#039;, &#039;class&#039;=&amp;gt;&#039;headingimage&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Again we are using the html_writer to do the work, however this time we are producing an img tag. You&#039;ll also notice the use of the pix_url function. Because our renderer is extending the core_renderer we can make use of all of its functions, pix_url being a useful one in this case.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content .= parent::heading($text, $level, $classes, $id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Of course the other thing we can do in this case is still use the core_renderers heading method to produce the h* tag as we are just adding content around it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content .= html_writer::end_tag(&#039;div&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The final thing to do is close the div that we opened on line one. Again we can do this with the html_writer.&lt;br /&gt;
&lt;br /&gt;
Before testing it there are a few more things we need to do:&lt;br /&gt;
&lt;br /&gt;
1. Create an image called headingpic.png and put it into a directory called pix located within your theme directory - &#039;&#039;/theme/overridetest/pix/headingpic.png&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Create a CSS file called overridetest.css within a directory called style within your theme directory - &#039;&#039;/theme/overridetest/style/overridetest.css&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Add into overridetest.css the following two lines of css.&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
.headingcontainer .headingimage {float:left;margin-right:1em;}&lt;br /&gt;
.headingcontainer h2,&lt;br /&gt;
.headingcontainer h3,&lt;br /&gt;
.headingcontainer h4,&lt;br /&gt;
.headingcontainer h5,&lt;br /&gt;
.headingcontainer h6 {text-align:left;}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
4. Add the following line to the bottom of the config.php file&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;sheets = Array(&#039;overridetest&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that done if you now view a page within your Moodle installation you should see the difference.&lt;br /&gt;
&lt;br /&gt;
[[image:overriding_a_renderer_01.jpg]]&lt;br /&gt;
&lt;br /&gt;
As you can see from the clipping above heading now have our image next to the text and are left aligned.&lt;br /&gt;
&lt;br /&gt;
==Finding renderers to override==&lt;br /&gt;
&lt;br /&gt;
Identifying renderers and locating the files where they are located is necessary in order to override them.&lt;br /&gt;
&lt;br /&gt;
Renderers should always be located in a file ending with &#039;&#039;&#039;renderer.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The renderer.php file should always be located in the base directory of a component, e.g.&lt;br /&gt;
&lt;br /&gt;
* /webservice/renderer.php&lt;br /&gt;
* /mod/forum/renderer.php&lt;br /&gt;
* /mod/workshop/allocation/manual/renderer.php&lt;br /&gt;
&lt;br /&gt;
or in the &amp;lt;plugindir&amp;gt;/classes/ folder when used with autoloading.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the core renderer which is located in &#039;&#039;/lib/outputrenderers.php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
There is also a routine way to name renderers much like the process for naming a theme&#039;s overriding renderer.&lt;br /&gt;
&lt;br /&gt;
It should always be made up of the following three components joined by underscores:&lt;br /&gt;
# &#039;&#039;&#039;component&#039;&#039;&#039; This is the component the renderer belongs too, e.g. block, mod, or core.&lt;br /&gt;
# &#039;&#039;&#039;name&#039;&#039;&#039; This is the name of what ever the component is, e.g. forum, workshop, or wiki.&lt;br /&gt;
# &#039;&#039;&#039;renderer&#039;&#039;&#039; They should always be completed by the word renderer.&lt;br /&gt;
&lt;br /&gt;
The following are examples of renderers currently in use within Moodle:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class core_webservice_renderer {}&lt;br /&gt;
class mod_forum_renderer {}&lt;br /&gt;
class workshopallocation_manual_renderer {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again the only exception to this is the core renderer which is just &#039;&#039;&#039;core_renderer&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Overriding a component&#039;s renderer==&lt;br /&gt;
&lt;br /&gt;
Overriding a component&#039;s renderer works almost exactly the same as overriding a core renderer.&lt;br /&gt;
&lt;br /&gt;
As a matter of fact there are quite some renderers that also have &#039;core&#039; in their name, which can be a bit confusing.&lt;br /&gt;
&lt;br /&gt;
One pitfall is that, in order to extend such a renderer, it&#039;s class definition must be loaded first (unless you use autoloading).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is an example of how to override the calendar renderer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1. Within your renderers.php as created above add the line that loads the calendar&#039;s core_calendar_renderer class definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
include_once($CFG-&amp;gt;dirroot . &amp;quot;/calendar/renderer.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Add the theme_overridetest_core_calendar_renderer class definition that extends core_calendar_renderer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
include_once($CFG-&amp;gt;dirroot . &amp;quot;/calendar/renderer.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_calendar_renderer extends core_calendar_renderer {&lt;br /&gt;
&lt;br /&gt;
   // place your overridden methods (functions) here.&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note again:&lt;br /&gt;
&lt;br /&gt;
* The name of the renderer is VERY important it is made up of three sections joined by underscores:&lt;br /&gt;
: &#039;&#039;theme&#039;&#039;: This will always be the same when overriding renderers from the theme.&lt;br /&gt;
: &#039;&#039;overridetest&#039;&#039;: This is of course the name of our theme, and should be the name of the theme the renderer is being overridden from.&lt;br /&gt;
: &#039;&#039;core_calendar_renderer&#039;&#039;: This is the renderer that we are overriding.&lt;br /&gt;
* The renderer should always extend the renderer it is overriding. This ensures we don&#039;t need to override every method the renderer offers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With the theme_overridetest_core_calendar_renderer class defined you can now override the methods that need overriding.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For example to stop the button to add an event from being rendered:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
include_once($CFG-&amp;gt;dirroot . &amp;quot;/calendar/renderer.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class theme_overridetest_core_calendar_renderer extends core_calendar_renderer {&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
     * Disabled creation of the button to add a new event (Was: Creates a button to add a new event)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $courseid&lt;br /&gt;
     * @param int $day&lt;br /&gt;
     * @param int $month&lt;br /&gt;
     * @param int $year&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    protected function add_event_button($courseid, $day=null, $month=null, $year=null) {&lt;br /&gt;
    	return &#039;&#039;;&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;
&lt;br /&gt;
The same principle applies for all other renderers.&lt;br /&gt;
&lt;br /&gt;
== Namespaces ==&lt;br /&gt;
&lt;br /&gt;
Renderers can also be used with code that uses namespaces. When creating or overriding new renderers with namespaces, be sure to use &amp;quot;output&amp;quot; as the second level namespace to comply with the rules for namespaces. Non-namespaced renderers can be overridden by a namespaced renderer and vice-versa - this leads to a complex search strategy when looking for overridden renderers. &lt;br /&gt;
&lt;br /&gt;
For example: the renderer for the component &amp;quot;mod_assign&amp;quot; with subtype &amp;quot;custom&amp;quot; and target &amp;quot;cli&amp;quot; could exist in any of these classes (listed in priority order):&lt;br /&gt;
&lt;br /&gt;
* theme_child\\output\\mod_assign\\custom_renderer_cli&lt;br /&gt;
* theme_child\\output\\mod_assign\\custom\\renderer_cli&lt;br /&gt;
* theme_child_mod_assign_custom_renderer_cli&lt;br /&gt;
* theme_parent\\output\\mod_assign\\custom_renderer_cli&lt;br /&gt;
* theme_parent\\output\\mod_assign\\custom\\renderer_cli&lt;br /&gt;
* theme_parent_mod_assign_custom_renderer_cli&lt;br /&gt;
* mod_assign\\output\\custom_renderer_cli&lt;br /&gt;
* mod_assign\\output\\custom\\renderer_cli&lt;br /&gt;
* mod_assign_custom_renderer_cli&lt;br /&gt;
* theme_child\\output\\mod_assign\\custom_renderer&lt;br /&gt;
* theme_child\\output\\mod_assign\\custom\\renderer&lt;br /&gt;
* theme_child_mod_assign_custom_renderer&lt;br /&gt;
* theme_parent\\output\\mod_assign\\custom_renderer&lt;br /&gt;
* theme_parent\\output\\mod_assign\\custom\\renderer&lt;br /&gt;
* theme_parent_mod_assign_custom_renderer&lt;br /&gt;
* mod_assign\\output\\custom_renderer&lt;br /&gt;
* mod_assign\\output\\custom\\renderer&lt;br /&gt;
* mod_assign_custom_renderer&lt;br /&gt;
&lt;br /&gt;
For more examples of possible class names for renderers see lib/tests/outputfactories_test.php&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Adding courses and categories to the custom menu]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Automatic_class_loading]]&lt;br /&gt;
* [[Coding_style#Namespaces]]&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Page_API&amp;diff=34994</id>
		<title>Page API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Page_API&amp;diff=34994"/>
		<updated>2012-08-20T18:25:27Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Page API is used to set up the current page, add JavaScript, and configure how things will be displayed to the user.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The Page API is an integral part of any Moodle page. It allows the developer to set things up the way they envisage it. Through the Page API you can set things like the title, initial heading, where the user is for the navigation, and which layout you think the page should use.&lt;br /&gt;
&lt;br /&gt;
This document starts off with a simple example, and then proceeds to provide a more complete description of how to set up a page for display.&lt;br /&gt;
&lt;br /&gt;
==A simple example==&lt;br /&gt;
This example covers how to set up a basic page for use within an activity plugin and is undoubtedly the simplest example as much of the work is done behind the scenes for you.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// File: /mod/mymodulename/view.php&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
$cmid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$cm = get_coursemodule_from_id(&#039;mymodulename&#039;, $cmid, 0, false, MUST_EXIST);&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;course), &#039;*&#039;, MUST_EXIST);&lt;br /&gt;
&lt;br /&gt;
require_login($course, true, $cm);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/mod/mymodulename/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id));&lt;br /&gt;
$PAGE-&amp;gt;set_title(&#039;My modules page title&#039;);&lt;br /&gt;
$PAGE-&amp;gt;set_heading(&#039;My modules page heading&#039;);&lt;br /&gt;
&lt;br /&gt;
// The rest of your code goes below this.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
I&#039;m going to assume you know what the first four lines are doing, if not you are starting in the wrong place.&lt;br /&gt;
&lt;br /&gt;
So lets start at require_login and assume you already have the course and course module objects ready to use. When you call require_login part of the magic it does for you is set up the basic for the current page.&amp;lt;br /&amp;gt;&lt;br /&gt;
In the case of the example above because require_login is given a course and course module it is already setting up much of the page for you. It is giving the course and course module objects to the page, setting the context for the page to the course modules context, and setting the page layout to &#039;&#039;incourse&#039;&#039; so that you get the standard look of a course module.&lt;br /&gt;
&lt;br /&gt;
The set up that we are having to do is as follows:&lt;br /&gt;
# Set the URL for the page. This MUST be done.&lt;br /&gt;
# Set a title for the page. Most likely will be shown in the &amp;lt;title&amp;gt; tag.&lt;br /&gt;
# Set the heading for the page. Most likely used in the pages header.&lt;br /&gt;
&lt;br /&gt;
It&#039;s important to mention that this has to be done before output starts. That means you must set up the page before the header is printed and before you instantiate any moodleform instances.&lt;br /&gt;
&lt;br /&gt;
And that is it, if you were to add a bit of simple output there you would get a page that already looks like other module pages you would have seen. Simple as.&lt;br /&gt;
&lt;br /&gt;
==$PAGE The Moodle page global==&lt;br /&gt;
For every page request Moodle sets up a couple of global structures that you will likely need. $DB the database object, and $CFG which stores configuration are two that you are likely already aware of. $PAGE is the focus of this article, it is a moodle_page instance that stores all of the information and is used by the output library $OUTPUT when displaying the page.&amp;lt;br /&amp;gt;&lt;br /&gt;
It&#039;s important to note the difference between $PAGE and $OUTPUT, $PAGE is for setting up the page and $OUTPUT is for displaying the page. $PAGE contains lots of logic and magic, $OUTPUT is purely about display and does little more than produce HTML.&lt;br /&gt;
&lt;br /&gt;
==Setting up the page==&lt;br /&gt;
When creating a page in Moodle there are a couple of things that you must set, and a couple of things that get set for you in many cases but not all of the time.&lt;br /&gt;
&lt;br /&gt;
===URL===&lt;br /&gt;
This is an absolute must, failing to set this will lead Moodle to display an error that it has not been set.&amp;lt;br /&amp;gt;&lt;br /&gt;
It can be set in the following manner:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_url(new moodle_url(&#039;/page/to/your/file.php&#039;, array(&#039;key&#039; =&amp;gt; &#039;value&#039;, &#039;id&#039; =&amp;gt; 3)));&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/page/to/your/file.php&#039;, array(&#039;key&#039; =&amp;gt; &#039;value&#039;, &#039;id&#039; =&amp;gt; 3));&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/page/to/your/file.php?key=value&amp;amp;id=3&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code sets the page URL 3 times, and highlights the 3 different ways you can set the URL. Either of the first two methods are the preferred way as it provides 100% accuracy when processing the URL. Internally set_url() converts what ever you give it to a moodle_url object.&lt;br /&gt;
&lt;br /&gt;
The URL that you give to the page is going to be use by a lot of Moodle core API&#039;s. Most importantly it is going to be used to create the navigation for your page so it&#039;s very important you set it accurately.&lt;br /&gt;
&lt;br /&gt;
===Context===&lt;br /&gt;
This is an absolute must as well, however in many cases it will be set for you magically by Moodle.&lt;br /&gt;
&lt;br /&gt;
In order to set the context for the page you must provide a context object, in Moodle 2.2 and greater this will look as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Moodle 2.2 and greater&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_system::instance());&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_coursecat::instance($categoryid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_course::instance($courseid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_module::instance($moduleid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0+, and Moodle 2.1+ the following is the equivalent code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Moodle 2.2 and greater&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_system_context());&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_COURSECAT, $categoryid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_COURSE, $courseid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_MODULE, $moduleid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both examples above setting different types of contexts has been illustrated however you should only ever call set_context() once with the context that is most appropriate to the page you are creating.&amp;lt;br /&amp;gt;&lt;br /&gt;
If it is a plugin then the context to use would be the context you are using for your capability checks.&lt;br /&gt;
&lt;br /&gt;
As mentioned above the other thing to be aware of is that in some circumstances this gets automatically set for you.&amp;lt;br /&amp;gt;&lt;br /&gt;
If your script calls require_login (and most scripts have to) and you are providing a course, or a module to your require login call then you will not need to call set_context().&amp;lt;br /&amp;gt;&lt;br /&gt;
This is because require_login handles it for you.&lt;br /&gt;
&lt;br /&gt;
If your script doesn&#039;t call require_login, or you don&#039;t call it with a course and/or module then you will need to manually set the context as shown.&lt;br /&gt;
&lt;br /&gt;
===Optional set up===&lt;br /&gt;
The following are optional extras you can set up against the PAGE object that you are likely to encounter throughout Moodle core, and are likely to want to use yourself.&lt;br /&gt;
====Page layout====&lt;br /&gt;
The following code sets the pages layout to the standard layout, the most generic layout in the arsenal.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_pagelayout(&#039;standard&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When setting the page layout you should use the layout that is the closest match to the page you are creating. Layouts are used by themes to determine what is is shown on the page. The most prominent difference between layouts is the block regions they support. The default layout `&#039;&#039;base&#039;&#039;` for example doesn&#039;t normally have any block regions at all, where as normally `&#039;&#039;standard&#039;&#039;` has the most generic layout and several block regions.&lt;br /&gt;
&lt;br /&gt;
There are dozens of different layouts that can be, and are used throughout Moodle core that you can use within your code. For a full list of common layouts you are best too look at theme/base/config.php or refer to the list below.&lt;br /&gt;
&lt;br /&gt;
Note: It&#039;s important to know that the theme determines what layouts are available and how each looks. If you select a layout that the theme doesn&#039;t support then it will revert to the default layout while using that theme.&amp;lt;br /&amp;gt;Themes are also able to specify additional layouts, however its important to spot them and know that while they may work with one theme they are unlikely to work as you expect with other themes.&lt;br /&gt;
&lt;br /&gt;
====Base theme page layouts====&lt;br /&gt;
The following is a list of the layouts defined by the base theme. Theme designers are encouraged to make the base theme a parent of their custom theme so you can be sure that in 99% of cases these layouts will be available.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layout&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| base&lt;br /&gt;
| Most backwards compatible layout without the blocks. This is the layout used by default.&lt;br /&gt;
|-&lt;br /&gt;
| standard&lt;br /&gt;
| Standard layout with blocks, this is recommended for most pages with general information&lt;br /&gt;
|-&lt;br /&gt;
| course&lt;br /&gt;
| The course main page uses this layout.&lt;br /&gt;
|-&lt;br /&gt;
| coursecategory&lt;br /&gt;
| Category course listings.&lt;br /&gt;
|-&lt;br /&gt;
| incourse&lt;br /&gt;
| Used for areas within a course, typical for modules. Default page layout if $cm specified in require_login().&lt;br /&gt;
|-&lt;br /&gt;
| frontpage&lt;br /&gt;
| The site home page uses this.&lt;br /&gt;
|-&lt;br /&gt;
| admin&lt;br /&gt;
| Admin and settings pages as well as server administration scripts.&lt;br /&gt;
|-&lt;br /&gt;
| mydashboard&lt;br /&gt;
| The users dashboard.&lt;br /&gt;
|-&lt;br /&gt;
| mypublic&lt;br /&gt;
| A users public profile uses this layout.&lt;br /&gt;
|-&lt;br /&gt;
| login&lt;br /&gt;
| The login screen.&lt;br /&gt;
|-&lt;br /&gt;
| popup&lt;br /&gt;
| Pages that appear in popup windows, usually no navigation, blocks, or header.&lt;br /&gt;
|-&lt;br /&gt;
| frametop&lt;br /&gt;
| Used for the outermost content of a page constructed with frames. Usually no blocks and minimal footer.&lt;br /&gt;
|-&lt;br /&gt;
| embedded&lt;br /&gt;
| Embedded pages such as content for iframes/objects. Needs as much space as possible usually no blocks, header, or footer.&lt;br /&gt;
|-&lt;br /&gt;
| maintenance&lt;br /&gt;
| Used during upgrade, installation, and when maintenance mode is enabled.&lt;br /&gt;
|-&lt;br /&gt;
| print&lt;br /&gt;
| Gets used when printing a page. Normally just a simple header and no blocks.&lt;br /&gt;
|-&lt;br /&gt;
| redirect&lt;br /&gt;
| A special layout used during a redirect. Normally with content only.&lt;br /&gt;
|-&lt;br /&gt;
| report&lt;br /&gt;
| Used for reports within Moodle. Special layout designed to handle horizontal scrolling in a nice way.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Title====&lt;br /&gt;
Setting an appropriate title is certainly a must for any properly designed page. While it is optional it is highly recommended that you set the title.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_title(&#039;This is my title&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When setting the title for the page you need to provide just the string you want to use for the title. It should be a basic string and contain no HTML. Any HTML will be stripped out as the title is used within the &amp;lt;title&amp;gt; tag in the HTML head.&lt;br /&gt;
&lt;br /&gt;
====Heading====&lt;br /&gt;
Like title it is highly recommended that you set a meaningful heading for the page, although it is optional.&amp;lt;br /&amp;gt;The heading is normally displayed at the top of the page before the rest of the content starts. However it is up to the layout defined by the theme as to where it is displayed. Not all layouts will display a heading but I encourage you to always set one even if you are using a layout that doesn&#039;t support headings. This way if you are using a theme that uses a heading on every page regardless of layout things still look consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_heading(get_string(&#039;pluginname&#039;, &#039;local_myplugin&#039;), 3);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When setting a heading there is just one argument, the string to use for the heading. It should be a basic string and contain no HTML.&lt;br /&gt;
&lt;br /&gt;
=== Advanced set up ===&lt;br /&gt;
The following are advanced optional methods you can call to further set up your page. In most cases you will never need to use these.&lt;br /&gt;
&lt;br /&gt;
; set_activity_record : If you have called require_login with a course module, or you have manually set a course module on $PAGE then one other thing you may want to do is set the activity module record on $PAGE as well.&amp;lt;br /&amp;gt;This is best done when you have already fetched the activity record yourself in which case manually setting the activity record may reduce the number of queries for the page by 1.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_activity_record($activityrecord)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_blocks_editing_capability : Using this method you can set an additional capability that users must posses before being able to edit blocks on this page.&amp;lt;br /&amp;gt;By default &#039;moodle/site:manageblocks&#039; is used however there are sometimes reasons to use a different capability.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_blocks_editing_capability($strcapability)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_button : This allows you to set some HTML that will be shown in the navigation bar where the `Turn on editing` button normally lives.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_button($htmlstring)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_cacheable : By setting this to false the page will be sent with headers to prevent the client from caching the page. Defaults to true.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_cacheable(true/false)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_category_by_id : Allows you to set a category that this page is displaying. Calling this will force the $PAGE-&amp;gt;course to be set to the front page course.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_category_by_id($categoryid)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_cm : Like set page above, sometimes you need to manually set the course module for $PAGE. Again you must set the context to the context of the course module if you call this.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_cm($coursemodulerecord)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_course : This allows you to set the course the page belongs to. Normally when you call require_login the course you give it automatically gets sent to $PAGE for you.&amp;lt;br /&amp;gt;However if you don&#039;t want to require login for the course, but you need it in $PAGE then you can call set_course and provide it.&amp;lt;br /&amp;gt;Note that if you do this then you MUST use the context of the course when calling set_context().&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_course($courserecord)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_docs_path : Normally this gets automatically constructed for you, however in some circumstances you may want to manually set it.&amp;lt;br /&amp;gt;This allows you to have several pages that all point to the same docs page rather than requiring a docs page for each.&amp;lt;br /&amp;gt;The docs page link is normally shown by a theme in the footer.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_docs_path($strpath)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_focuscontrol : If you pass this method an element id when the page loads on the client focus will be shifted to the element with the corresponding id.&amp;lt;br /&amp;gt;Using this function is a REALLY bad idea in most situations because changing focus automatically in a browser is a nightmare for the vision impaired and those using screen readers.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_focuscontrol($controlid)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_headingmenu : This allows you to set some HTML that will be shown next to the pages main heading where the language select box normally lives.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_headingmenu($htmlstring)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_other_editing_capability : Can be used to set an additional capability that the user must posses before they can turn editing on for this page.&amp;lt;br /&amp;gt;This is useful if you can an editing more for your page that is more than just editing blocks.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_other_editing_capability($strcapability)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_pagetype : This gets automatically set up for by default to the path of your file e.g. mod/mymod/index.php will set up as mod-mymod-index.&amp;lt;br /&amp;gt;This is absolutely fine in 99% of cases however every now and again there is a reason to override it.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_pagetype($strpagetype)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_periodic_refresh_delay : If set a meta tag gets added to the page header causing it to refresh intermittently.&amp;lt;br /&amp;gt;This is rarely needed but can be useful if you need to automatically refresh the likes of a chat page, or news feed.&amp;lt;br /&amp;gt;Today it is not recommended to use this, but instead to create a means of getting additional content via AJAX.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_periodic_refresh_delay($intdelay)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_popup_notification_allowed : Allow or disallow popup notifications on this page. Things like messaging can cause messages to popup at the bottom of the screen sometimes.&amp;lt;br /&amp;gt;On some pages this functionality is not desired and can be stopped by calling this method and using false as the first argument.&amp;lt;br /&amp;gt;Popups are allowed by default.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_popup_notification_allowed(true/false)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_subpage : If context-&amp;gt;id and pagetype are not enough to uniquely identify this page and you need to include another string to make it more unique you can do it by calling this method setting a custom sub page type.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_subpage($strsubpage)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; add_body_class : Adds a CSS class to the body tag that will be printed by the Output API as part of the header.&amp;lt;br /&amp;gt;This is useful for adding classes to the body tag that describe the content of the page and may be required for styling the whole page, or for including indicator classes that may be useful to look for in JavaScript.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;add_body_class($strcssclass)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; add_body_classes : Adds an array of CSS classes to the body tag. Have a look at the above comment for &#039;&#039;&#039;add_body_class&#039;&#039;&#039; for more details.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;add_body_classes($arrayofclasses)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Getting information about the page==&lt;br /&gt;
As well of setting up the page you can of course get information back from it about the page it has been set up to display.&amp;lt;br /&amp;gt;&lt;br /&gt;
Anything you set against the page can be retrieved as can any information that was set magically for you by other methods.&lt;br /&gt;
&lt;br /&gt;
The following are the most interesting and likely useful things you can get back from the page.&lt;br /&gt;
&lt;br /&gt;
; activityrecord : The activityrecord will be the record from the database that relates to the cm that was set by require_login, or manually by your code.&amp;lt;br /&amp;gt;For example if you provided a $cm instance that related to a forum this will be a row from the forum table.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;activityrecord;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; blockmanager : This is the block manager responsible for loading the all of the blocks that will be shown on the page.&amp;lt;br /&amp;gt;For more information see the [[Blocks API]].&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;blockmanager;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; bodyid : The id that will be given to the body tag when the page is displayed.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;bodyid&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; categories : An array of all the categories the page course belongs to, starting with the immediately containing category.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;categories&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; category : The category that the page course belongs to.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;category&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; cm : The course module that has been set for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;cm&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; course : The course that has been set for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;course&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; devicetypeinuse : The device the user is using browse the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;devicetypeinuse&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; headerprinted : Is true if the page header has already been printed. &lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;headerprinted&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; heading : The page heading.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;heading&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; navbar : Gets a reference to the pages navigation bar so that you can interact with that. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;navbar&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; navigation : Gets a reference to the navigation for the page. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; requires : Gets the page requirements manager that handles any JavaScript and special CSS requirements for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;requires&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; settingsnav : Gets the settings navigation for the page. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;settingsnav&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; theme : Gets the theme that is being used for the page. Is a theme_config object.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;theme&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; title : Gets the title for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;title&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; url : Gets the URL that was set for the page. Is a moodle_url object.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;url&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==FAQs==&lt;br /&gt;
&lt;br /&gt;
; I don&#039;t have any blocks on my page? : This has happened because you have not set a page layout that uses blocks OR you have set it after output has started. Once output has started you cannot change integral aspects of that page that are used for the initial output. Included is the page title, heading, url and layout.&lt;br /&gt;
&lt;br /&gt;
; I am getting a notice about not having set the page URL but I have set it? : As above you must set up the page before output starts, trying to do so will lead to notices and developer warnings about having things in the wrong order.&lt;br /&gt;
&lt;br /&gt;
; What starts output? : Output starts when either the script calls echo $OUTPUT-&amp;gt;header OR a moodleform is instantiated.&lt;br /&gt;
&lt;br /&gt;
==Related API&#039;s==&lt;br /&gt;
There are a couple of API&#039;s that are closely related to the Page API that you should be aware of as well.&lt;br /&gt;
&lt;br /&gt;
===Output API===&lt;br /&gt;
The output API is an immediate relation of the page API. The page API is about setting things up, whereas the output API is all about displaying things.&lt;br /&gt;
It&#039;s through the output API that content is actually produced, and much of the information you set up through the page is used to customise what is produced, and fill in the general blanks of any page (such as title and heading.&lt;br /&gt;
&lt;br /&gt;
See the [[Output API]] documentation for more information.&lt;br /&gt;
&lt;br /&gt;
===Page requirements API===&lt;br /&gt;
The page requirements API allows you the developer to include additional CSS, and JavaScript resources that should be included with the page, and to include JavaScript calls within the page through a variety of means.&lt;br /&gt;
Technically this API is part of the Output API mentioned above, however it deserves special mention. If you are going to be using any JavaScript or CSS within your page you will need to know about this.&lt;br /&gt;
&lt;br /&gt;
See the [[Output API]] documentation for more information on the page requirements API.&lt;br /&gt;
&lt;br /&gt;
===Navigation API===&lt;br /&gt;
The final API to mention is the navigation API. This again is integral to both the page and output API and is used to recognise the context of the content being displayed and ensure that the correct blocks and navigaiton structure are loaded for the context.&lt;br /&gt;
There is a good chance that you will encounter a need to customise the navigation early on in plugin page development and it&#039;s important to be aware of this important API.&lt;br /&gt;
&lt;br /&gt;
See the [[Navigation API]] documentation for more information on the page requirements API.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]] : A list of all the core API&#039;s in Moodle.&lt;br /&gt;
* [[Output API]] : The Output API.&lt;br /&gt;
* [[Navigation API]] : The Navigation API.&lt;br /&gt;
* [http://moodle.org/mod/forum/view.php?id=55 General developer forum] : The place to ask question you may have about the Page API.&lt;br /&gt;
* MDL-30977 : The issue to see the Page API properly documented.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Access_API&amp;diff=34993</id>
		<title>Access API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Access_API&amp;diff=34993"/>
		<updated>2012-08-20T18:18:05Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}The Access API gives you functions so you can determine what the current user is allowed to do. It also allows modules to extend Moodle with new capabilities. &lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Moodle is using a role based access control model. Most entities in Moodle (system, users, course categories, courses, modules and blocks) are represented by contexts that are arranged in a tree like hierarchy called context tree. Role is a set of capability definitions, each capability usually represents an ability of user to do something. Roles are defined at the top most system context level. Role definitions can be overridden at lower context levels. User access control is calculated from the definitions of roles assigned to users.&lt;br /&gt;
&lt;br /&gt;
All users that did not log-in yet automatically get the default role defined in $CFG-&amp;gt;notloggedinroleid, it is not possible to assign any other role to this non-existent user id. There is one special guest user account that is user when user logs in using the guest login button or when guest autologin is enabled. Again you can not assign any roles to the guest account directly, this account gets the $CFG-&amp;gt;guestroleid automatically. All other authenticated users get the default user role specified in $CFG-&amp;gt;defaultuserroleid and in the frontpage context the role specified in $CFG-&amp;gt;defaultfrontpageroleid.&lt;br /&gt;
&lt;br /&gt;
==How to define new capabilities in plugins==&lt;br /&gt;
&lt;br /&gt;
Capabilities are defined by $capabilities array defined in db/access.php files. The name of the capability consists of &amp;quot;plugintype/pluginname:capabilityname&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $capabilities = array(&lt;br /&gt;
    &#039;mod/folder:managefiles&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_SPAM,&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;editingteacher&#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;
Where the meaning of array keys is:&lt;br /&gt;
* riskbitmask - associated risks. These are explained on [[Hardening new Roles system]].&lt;br /&gt;
* captype - &#039;&#039;read&#039;&#039; or &#039;&#039;write&#039;&#039; capability type, for security reasons system prevents all write capabilities for guest account and not-logged-in users&lt;br /&gt;
* contextlevel - specified as context level constant, the lowest level where is this capability usable, plugins may hardcode exceptions if they use capability in more contexts&lt;br /&gt;
* archetypes - specifies defaults for roles with standard archetypes, this is used in installs, upgrades and when resetting roles (it is recommended to use only CAP_ALLOW here)&lt;br /&gt;
* clonepermissionsfrom - when you are adding a new capability, you can tell Moodle to copy the permissions for each role from the current settings for another capabilty. This may give better defaults than just using archetypes for administrators who have heavily customised their roles configuration. The full syntax is: &amp;lt;tt&amp;gt;&#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/quiz:attempt&#039;,&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &#039;&#039;In releases before May 2012 clonepermissionsfrom works only inside individual plugins or only in core, in later releases plugins may also clone permissions from core, success of other cloning operations depends on upgrade order.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It is necessary to bump up plugin version number after any change in db/access.php.&lt;br /&gt;
&lt;br /&gt;
The capability names are defined in plugin language files, the name of the string consists of &amp;quot;pluginname:capabilityname&amp;quot;, in the example above it would be:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $string[&#039;folder:managefiles&#039;] = &#039;Manage files in folder module&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Useful functions and classes==&lt;br /&gt;
&lt;br /&gt;
===Context fetching===&lt;br /&gt;
&lt;br /&gt;
In plugins context instances are usually only instantiated because they are instantiated and deleted automatically by the system.&lt;br /&gt;
&lt;br /&gt;
Fetching by object id:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $systemcontext = context_system::instance();&lt;br /&gt;
 $usercontext = context_user::instance($user-&amp;gt;id);&lt;br /&gt;
 $categorycontext = context_coursecat::instance($category-&amp;gt;id);&lt;br /&gt;
 $coursecontext = context_course::instance($course-&amp;gt;id);&lt;br /&gt;
 $contextmodule = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fetching by context id:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $context = context::instance_by_id($contextid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* by default exception is thrown if context can not be created&lt;br /&gt;
* deleted users do not have contexts any more&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are multiple deprecated context related functions since 2.2, it is not necessary to replace them immediately. The following two functions are equivalent to the context fetching examples above:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function get_context_instance($contextlevel, $instance = 0, $strictness = IGNORE_MISSING)&lt;br /&gt;
 function get_context_instance_by_id($id, $strictness = IGNORE_MISSING)&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Determining that a user has a given capability===&lt;br /&gt;
&lt;br /&gt;
When implementing access control always ask &amp;quot;Does the user have capability to do something?&amp;quot;. It is incorrect to ask &amp;quot;Does the user have a role somewhere?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====has_capability()====&lt;br /&gt;
has_capability() is the most important function:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function has_capability($capability, context $context, $user = null, $doanything = true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check whether a user has a particular capability in a given context. For example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
 has_capability(&#039;mod/folder:managefiles&#039;, $context)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default checks the capabilities of the current user, but you can pass a different userid. By default will return true for admin users, it is not recommended to use false here.&lt;br /&gt;
&lt;br /&gt;
====require_capability()====&lt;br /&gt;
Function require_capability() is very similar, it is throwing access control exception if user does not have the capability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function require_capability($capability, context $context, $userid = null, $doanything = true, $errormessage = &#039;nopermissions&#039;, $stringfile = &#039;&#039;) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Enrolment functions===&lt;br /&gt;
&lt;br /&gt;
Since Moodle  2.2 there is a new concept of user enrolments, they are fully independent from the roles and capabilities, see [[Enrol API]] for more information.&lt;br /&gt;
&lt;br /&gt;
Capabilities are very often used in combination with enrolment status.&lt;br /&gt;
&lt;br /&gt;
====is_enrolled()====&lt;br /&gt;
Is user participating in the course? Returns true for students and teachers, false for administrators and other managers. User enrolments can be either active or suspended, suspended users can not enter the course (unless there is some kind of guest access allowed) and are usually hidden in the UI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function is_enrolled(context $context, $user = null, $withcapability = &#039;&#039;, $onlyactive = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Good example is choice module where we have one slot for each participant, people that are not enrolled are not allowed to vote &amp;lt;code&amp;gt;is_enrolled($context, $USER, &#039;mod/choice:choose&#039;)&amp;lt;/code&amp;gt;. Another example is assignment where users need to be enrolled and have capability to submit assignemnts &amp;lt;code&amp;gt;is_enrolled($this-&amp;gt;context, $USER, &#039;mod/assignment:submit&#039;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====get_enrolled_users()====&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to know the list of users that can participate in some activity.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function get_enrolled_sql(context $context, $withcapability = &#039;&#039;, $groupid = 0, $onlyactive = false)&lt;br /&gt;
 function get_enrolled_users(context $context, $withcapability = &#039;&#039;, $groupid = 0, $userfields = &#039;u.*&#039;, $orderby = &#039;&#039;, $limitfrom = 0, $limitnum = 0)&lt;br /&gt;
 function count_enrolled_users(context $context, $withcapability = &#039;&#039;, $groupid = 0)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example you want to know who is able to summit assignment right now:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$submissioncandidates = get_enrolled_users($modcontext, &#039;mod/assignment:submit&#039;, 0, true);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The assignment module needs to hold data for all users that are enrolled including the users with suspended enrolments and without any roles. Module developers may decide to purge all user data when user is fully unenrolled.&lt;br /&gt;
&lt;br /&gt;
SQL select from get_enrolled_sql() is often used for performance reasons - you can use it in joins to get specific information for only enrolled users.&lt;br /&gt;
&lt;br /&gt;
===Other related functions===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)&lt;br /&gt;
 function require_course_login($courseorid, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)&lt;br /&gt;
 function get_users_by_capability(context $context, $capability, $fields = &#039;&#039;, $sort = &#039;&#039;, $limitfrom = &#039;&#039;, $limitnum = &#039;&#039;,&lt;br /&gt;
                                  $groups = &#039;&#039;, $exceptions = &#039;&#039;, $doanything_ignored = null, $view_ignored = null, $useviewallgroups = false)&lt;br /&gt;
 function isguestuser($user = null)&lt;br /&gt;
 function isloggedin()&lt;br /&gt;
 function is_siteadmin($user_or_id = null)&lt;br /&gt;
 function is_guest(context $context, $user = null)&lt;br /&gt;
 function is_viewing(context $context, $user = null, $withcapability = &#039;&#039;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====require_login()====&lt;br /&gt;
&lt;br /&gt;
Each plugin script should include require_login() or require_course_login() after setting up PAGE-&amp;gt;url.&lt;br /&gt;
&lt;br /&gt;
this function does following:&lt;br /&gt;
* it verifies that user is logged in before accessing any course or activities (not-logged-in users can not enter any courses).&lt;br /&gt;
* user is logged in as gu&lt;br /&gt;
* verify access to hidden courses and activities&lt;br /&gt;
* verify experimental groupmembersonly access&lt;br /&gt;
* verify that user is either enrolled or has capability &#039;moodle/course:view&#039; or some enrol plugin gives them temporary guest access&lt;br /&gt;
* logs access to courses&lt;br /&gt;
&lt;br /&gt;
====require_course_login()====&lt;br /&gt;
&lt;br /&gt;
This function is supposed to be used only in activities that want to allow read access to content on the frontpage without logging-in. For example view resource files, reading of glossary  entries, etc.&lt;br /&gt;
&lt;br /&gt;
====isguestuser(), isloggedin() and is_siteadmin()====&lt;br /&gt;
&lt;br /&gt;
These function were previously needed for limiting of access of special accounts. It is usually not necessary any mor, because any &#039;&#039;&#039;write&#039;&#039;&#039; or &#039;&#039;&#039;risky&#039;&#039;&#039; capabilities are now automatically prevented in has_capability().&lt;br /&gt;
&lt;br /&gt;
It is strongly discouraged to use is_siteadmin() in activity modules, please use standard capabilities and enrolment status instead.&lt;br /&gt;
&lt;br /&gt;
====is_guest(), is_viewing() and is_enrolled()====&lt;br /&gt;
&lt;br /&gt;
In order to access course data one of these functions must return true for user:&lt;br /&gt;
* is_enrolled() - user has active record in user_enrolments table&lt;br /&gt;
* is_viewing() - user has &#039;moodle/course:view&#039; capability (may access course, but is not considered to be participant)&lt;br /&gt;
* is_guest() - user was given temporary guest access by some enrolment plugin&lt;br /&gt;
&lt;br /&gt;
====get_users_by_capability()====&lt;br /&gt;
&lt;br /&gt;
This method returns list of users with given capability, it ignores enrolment status and should be used only above the course context.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Roles]]&lt;br /&gt;
* [[Role archetypes]]&lt;br /&gt;
* [[Hardening new Roles system]]&lt;br /&gt;
* [[Roles and modules]]&lt;br /&gt;
* [[NEWMODULE Adding capabilities]]&lt;br /&gt;
* [[New permissions evaluation in 2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Access_API&amp;diff=34992</id>
		<title>Access API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Access_API&amp;diff=34992"/>
		<updated>2012-08-20T18:17:27Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}The Access API gives you functions so you can determine what the current user is allowed to do, and it allows modules to extend Moodle with new capabilities. &lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Moodle is using a role based access control model. Most entities in Moodle (system, users, course categories, courses, modules and blocks) are represented by contexts that are arranged in a tree like hierarchy called context tree. Role is a set of capability definitions, each capability usually represents an ability of user to do something. Roles are defined at the top most system context level. Role definitions can be overridden at lower context levels. User access control is calculated from the definitions of roles assigned to users.&lt;br /&gt;
&lt;br /&gt;
All users that did not log-in yet automatically get the default role defined in $CFG-&amp;gt;notloggedinroleid, it is not possible to assign any other role to this non-existent user id. There is one special guest user account that is user when user logs in using the guest login button or when guest autologin is enabled. Again you can not assign any roles to the guest account directly, this account gets the $CFG-&amp;gt;guestroleid automatically. All other authenticated users get the default user role specified in $CFG-&amp;gt;defaultuserroleid and in the frontpage context the role specified in $CFG-&amp;gt;defaultfrontpageroleid.&lt;br /&gt;
&lt;br /&gt;
==How to define new capabilities in plugins==&lt;br /&gt;
&lt;br /&gt;
Capabilities are defined by $capabilities array defined in db/access.php files. The name of the capability consists of &amp;quot;plugintype/pluginname:capabilityname&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $capabilities = array(&lt;br /&gt;
    &#039;mod/folder:managefiles&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_SPAM,&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;editingteacher&#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;
Where the meaning of array keys is:&lt;br /&gt;
* riskbitmask - associated risks. These are explained on [[Hardening new Roles system]].&lt;br /&gt;
* captype - &#039;&#039;read&#039;&#039; or &#039;&#039;write&#039;&#039; capability type, for security reasons system prevents all write capabilities for guest account and not-logged-in users&lt;br /&gt;
* contextlevel - specified as context level constant, the lowest level where is this capability usable, plugins may hardcode exceptions if they use capability in more contexts&lt;br /&gt;
* archetypes - specifies defaults for roles with standard archetypes, this is used in installs, upgrades and when resetting roles (it is recommended to use only CAP_ALLOW here)&lt;br /&gt;
* clonepermissionsfrom - when you are adding a new capability, you can tell Moodle to copy the permissions for each role from the current settings for another capabilty. This may give better defaults than just using archetypes for administrators who have heavily customised their roles configuration. The full syntax is: &amp;lt;tt&amp;gt;&#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/quiz:attempt&#039;,&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &#039;&#039;In releases before May 2012 clonepermissionsfrom works only inside individual plugins or only in core, in later releases plugins may also clone permissions from core, success of other cloning operations depends on upgrade order.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It is necessary to bump up plugin version number after any change in db/access.php.&lt;br /&gt;
&lt;br /&gt;
The capability names are defined in plugin language files, the name of the string consists of &amp;quot;pluginname:capabilityname&amp;quot;, in the example above it would be:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $string[&#039;folder:managefiles&#039;] = &#039;Manage files in folder module&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Useful functions and classes==&lt;br /&gt;
&lt;br /&gt;
===Context fetching===&lt;br /&gt;
&lt;br /&gt;
In plugins context instances are usually only instantiated because they are instantiated and deleted automatically by the system.&lt;br /&gt;
&lt;br /&gt;
Fetching by object id:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $systemcontext = context_system::instance();&lt;br /&gt;
 $usercontext = context_user::instance($user-&amp;gt;id);&lt;br /&gt;
 $categorycontext = context_coursecat::instance($category-&amp;gt;id);&lt;br /&gt;
 $coursecontext = context_course::instance($course-&amp;gt;id);&lt;br /&gt;
 $contextmodule = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fetching by context id:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $context = context::instance_by_id($contextid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* by default exception is thrown if context can not be created&lt;br /&gt;
* deleted users do not have contexts any more&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are multiple deprecated context related functions since 2.2, it is not necessary to replace them immediately. The following two functions are equivalent to the context fetching examples above:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function get_context_instance($contextlevel, $instance = 0, $strictness = IGNORE_MISSING)&lt;br /&gt;
 function get_context_instance_by_id($id, $strictness = IGNORE_MISSING)&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Determining that a user has a given capability===&lt;br /&gt;
&lt;br /&gt;
When implementing access control always ask &amp;quot;Does the user have capability to do something?&amp;quot;. It is incorrect to ask &amp;quot;Does the user have a role somewhere?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====has_capability()====&lt;br /&gt;
has_capability() is the most important function:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function has_capability($capability, context $context, $user = null, $doanything = true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check whether a user has a particular capability in a given context. For example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
 has_capability(&#039;mod/folder:managefiles&#039;, $context)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default checks the capabilities of the current user, but you can pass a different userid. By default will return true for admin users, it is not recommended to use false here.&lt;br /&gt;
&lt;br /&gt;
====require_capability()====&lt;br /&gt;
Function require_capability() is very similar, it is throwing access control exception if user does not have the capability.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function require_capability($capability, context $context, $userid = null, $doanything = true, $errormessage = &#039;nopermissions&#039;, $stringfile = &#039;&#039;) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Enrolment functions===&lt;br /&gt;
&lt;br /&gt;
Since Moodle  2.2 there is a new concept of user enrolments, they are fully independent from the roles and capabilities, see [[Enrol API]] for more information.&lt;br /&gt;
&lt;br /&gt;
Capabilities are very often used in combination with enrolment status.&lt;br /&gt;
&lt;br /&gt;
====is_enrolled()====&lt;br /&gt;
Is user participating in the course? Returns true for students and teachers, false for administrators and other managers. User enrolments can be either active or suspended, suspended users can not enter the course (unless there is some kind of guest access allowed) and are usually hidden in the UI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function is_enrolled(context $context, $user = null, $withcapability = &#039;&#039;, $onlyactive = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Good example is choice module where we have one slot for each participant, people that are not enrolled are not allowed to vote &amp;lt;code&amp;gt;is_enrolled($context, $USER, &#039;mod/choice:choose&#039;)&amp;lt;/code&amp;gt;. Another example is assignment where users need to be enrolled and have capability to submit assignemnts &amp;lt;code&amp;gt;is_enrolled($this-&amp;gt;context, $USER, &#039;mod/assignment:submit&#039;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====get_enrolled_users()====&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to know the list of users that can participate in some activity.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function get_enrolled_sql(context $context, $withcapability = &#039;&#039;, $groupid = 0, $onlyactive = false)&lt;br /&gt;
 function get_enrolled_users(context $context, $withcapability = &#039;&#039;, $groupid = 0, $userfields = &#039;u.*&#039;, $orderby = &#039;&#039;, $limitfrom = 0, $limitnum = 0)&lt;br /&gt;
 function count_enrolled_users(context $context, $withcapability = &#039;&#039;, $groupid = 0)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example you want to know who is able to summit assignment right now:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$submissioncandidates = get_enrolled_users($modcontext, &#039;mod/assignment:submit&#039;, 0, true);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The assignment module needs to hold data for all users that are enrolled including the users with suspended enrolments and without any roles. Module developers may decide to purge all user data when user is fully unenrolled.&lt;br /&gt;
&lt;br /&gt;
SQL select from get_enrolled_sql() is often used for performance reasons - you can use it in joins to get specific information for only enrolled users.&lt;br /&gt;
&lt;br /&gt;
===Other related functions===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)&lt;br /&gt;
 function require_course_login($courseorid, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)&lt;br /&gt;
 function get_users_by_capability(context $context, $capability, $fields = &#039;&#039;, $sort = &#039;&#039;, $limitfrom = &#039;&#039;, $limitnum = &#039;&#039;,&lt;br /&gt;
                                  $groups = &#039;&#039;, $exceptions = &#039;&#039;, $doanything_ignored = null, $view_ignored = null, $useviewallgroups = false)&lt;br /&gt;
 function isguestuser($user = null)&lt;br /&gt;
 function isloggedin()&lt;br /&gt;
 function is_siteadmin($user_or_id = null)&lt;br /&gt;
 function is_guest(context $context, $user = null)&lt;br /&gt;
 function is_viewing(context $context, $user = null, $withcapability = &#039;&#039;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====require_login()====&lt;br /&gt;
&lt;br /&gt;
Each plugin script should include require_login() or require_course_login() after setting up PAGE-&amp;gt;url.&lt;br /&gt;
&lt;br /&gt;
this function does following:&lt;br /&gt;
* it verifies that user is logged in before accessing any course or activities (not-logged-in users can not enter any courses).&lt;br /&gt;
* user is logged in as gu&lt;br /&gt;
* verify access to hidden courses and activities&lt;br /&gt;
* verify experimental groupmembersonly access&lt;br /&gt;
* verify that user is either enrolled or has capability &#039;moodle/course:view&#039; or some enrol plugin gives them temporary guest access&lt;br /&gt;
* logs access to courses&lt;br /&gt;
&lt;br /&gt;
====require_course_login()====&lt;br /&gt;
&lt;br /&gt;
This function is supposed to be used only in activities that want to allow read access to content on the frontpage without logging-in. For example view resource files, reading of glossary  entries, etc.&lt;br /&gt;
&lt;br /&gt;
====isguestuser(), isloggedin() and is_siteadmin()====&lt;br /&gt;
&lt;br /&gt;
These function were previously needed for limiting of access of special accounts. It is usually not necessary any mor, because any &#039;&#039;&#039;write&#039;&#039;&#039; or &#039;&#039;&#039;risky&#039;&#039;&#039; capabilities are now automatically prevented in has_capability().&lt;br /&gt;
&lt;br /&gt;
It is strongly discouraged to use is_siteadmin() in activity modules, please use standard capabilities and enrolment status instead.&lt;br /&gt;
&lt;br /&gt;
====is_guest(), is_viewing() and is_enrolled()====&lt;br /&gt;
&lt;br /&gt;
In order to access course data one of these functions must return true for user:&lt;br /&gt;
* is_enrolled() - user has active record in user_enrolments table&lt;br /&gt;
* is_viewing() - user has &#039;moodle/course:view&#039; capability (may access course, but is not considered to be participant)&lt;br /&gt;
* is_guest() - user was given temporary guest access by some enrolment plugin&lt;br /&gt;
&lt;br /&gt;
====get_users_by_capability()====&lt;br /&gt;
&lt;br /&gt;
This method returns list of users with given capability, it ignores enrolment status and should be used only above the course context.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Roles]]&lt;br /&gt;
* [[Role archetypes]]&lt;br /&gt;
* [[Hardening new Roles system]]&lt;br /&gt;
* [[Roles and modules]]&lt;br /&gt;
* [[NEWMODULE Adding capabilities]]&lt;br /&gt;
* [[New permissions evaluation in 2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Web_services_(2.0_onwards)&amp;diff=18881</id>
		<title>Web services (2.0 onwards)</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Web_services_(2.0_onwards)&amp;diff=18881"/>
		<updated>2011-05-06T18:28:54Z</updated>

		<summary type="html">&lt;p&gt;Ddelrio1986: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Adding web-services to a plugin (Moodle 2.0) ==&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
Web services are built and provided by the &#039;externallib.php&#039; file in the modules (or areas) directory. In this file is kept the external class that extends the &#039;external_api&#039; class and provides definitions for the incoming message format, outgoing message format and the worker functions for each service.&lt;br /&gt;
&lt;br /&gt;
Extract from courses externallib.php:&lt;br /&gt;
 defined(&#039;MOODLE_INTERNAL&#039;) || die;&lt;br /&gt;
 &lt;br /&gt;
 require_once(&amp;quot;$CFG-&amp;gt;libdir/externallib.php&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 class moodle_course_external extends external_api {&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Each web-service requires three methods:&lt;br /&gt;
1. A parameters function (appended with _parameters).&lt;br /&gt;
2. A return parameters function (appended with _returns).&lt;br /&gt;
3. And the worker function itself.&lt;br /&gt;
&lt;br /&gt;
For example the &#039;get_courses&#039; service has the following three methods:&lt;br /&gt;
 //Provides a description of the parameters&lt;br /&gt;
 public static function get_courses_parameters () {} &lt;br /&gt;
 &lt;br /&gt;
 //Does the work of collecting the requested data, creating adding deleting records etc.&lt;br /&gt;
 public static function get_courses ($options) {} &lt;br /&gt;
 &lt;br /&gt;
 //Provides a description of the structure for the data returned by get_courses (the worker function).&lt;br /&gt;
 public static function get_courses_returns () {}&lt;br /&gt;
&lt;br /&gt;
== Making a web-service (get_course_activities ==&lt;br /&gt;
&lt;br /&gt;
For this tutorial we are going to create a local plugin that extends the services available through the core course web-services. For information on how to setup a local plugin see []&lt;br /&gt;
&lt;br /&gt;
This tutorial creates a get_course_activities web-service.&lt;br /&gt;
&lt;br /&gt;
To create this new service we will need to create the static functions in the externallib.php file under /course and will need to add several database entries.&lt;br /&gt;
&lt;br /&gt;
=== What should the call do? A little planning ===&lt;br /&gt;
&lt;br /&gt;
With this web-service we want to be able to ask moodle what activities a course has. To do this we will need to provide the web-service call with the course id that we want the activities returned for.&lt;br /&gt;
&lt;br /&gt;
1. First we need to create the parameters function. We could start with any of them however it will be easier to define the inputs and outputs before moving onto the worker.&lt;br /&gt;
 //First draft&lt;br /&gt;
 public static function get_course_activities_parameters () {&lt;br /&gt;
  //The _parameters method only has one objective, to return a description of the input data structure.&lt;br /&gt;
  return new external_function_parameters();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We aren&#039;t done with this method yet. &lt;br /&gt;
&lt;br /&gt;
A quick explanation of external_function_parameters is in order. (At the moment this explanation is guess work). The external_function_parameters is a wrapper class for the external_single_structure class. You must return an external_function_parameters class in the _parameters function. If you don&#039;t Moodle will throw an &#039;Invalid parameters description&#039; error. &lt;br /&gt;
&lt;br /&gt;
2. Next add the expected input structure to the external_function_parameters object.&lt;br /&gt;
&lt;br /&gt;
 //Second draft&lt;br /&gt;
 public static function get_course_activities_parameters () {&lt;br /&gt;
  return new external_function_parameters (&lt;br /&gt;
   array(&lt;br /&gt;
    &#039;courseid&#039;=&amp;gt; new external_value(PARAM_INT, &#039;id of the course&#039;)&lt;br /&gt;
   )&lt;br /&gt;
  );&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Here we have added a single external_single_structure implicitly through the external_function_parameters object. We don&#039;t need anything more spectacular as we only want to provide one piece of data, the course id.&lt;br /&gt;
&lt;br /&gt;
To do this we add a named array with one key, value pair. The key is set to the name of the field: &#039;courseid&#039; and the value is set to an external_value object with a PARAM_INT type. &lt;br /&gt;
 &#039;courseid&#039;=&amp;gt; new external_value(PARAM_INT,&#039;id of the course&#039;)&lt;br /&gt;
&lt;br /&gt;
This completes the _parameters function for the web-service. Next we can move on and define what we want to see in return.&lt;br /&gt;
&lt;br /&gt;
3. Creating the _returns function (get_course_activities_returns)&lt;br /&gt;
&lt;br /&gt;
Differently to the _parameters function the _returns function doesn&#039;t require a specific object as its primary return value. Instead you can choose from any of the objects that inherit the external_description class.&lt;br /&gt;
&lt;br /&gt;
As a result we should start by taking a look at the kind of data and therefore the kind of data structure that we are going to expect returned to use from the service. We expect that a single course will have many activities and we aren&#039;t asking for activities from more than one course. Each activity will have a set of fields that contain the activity information such as id and type.&lt;br /&gt;
&lt;br /&gt;
This should give us a starting point roughly like this:&lt;br /&gt;
 //&lt;br /&gt;
 public static function get_course_activities_returns () {&lt;br /&gt;
  return new external_multiple_structure (&lt;br /&gt;
   new external_single_structure ( //This is used to represent a single activity.&lt;br /&gt;
    array(&lt;br /&gt;
    ), &#039;activity&#039;) //The description of what this element represents.&lt;br /&gt;
  )&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We have a basic outline of the top level data structures that we want returned. This was fairly simple as the above structure is what you&#039;re likely to need anytime you want to return a list of objects or &#039;items&#039;.&lt;br /&gt;
&lt;br /&gt;
4. Adding a description of the activity fields to be returned.&lt;br /&gt;
&lt;br /&gt;
Now we need to define what each activity item should look like. In reality when you develop a web-service you may switch between defining the return structure in the _returns function and writing the worker function (i.e what the author needed to do to write this tutorial).  We are going to concentrate just on finishing this function so that the description of the fields is in one place and we can follow a single train of thought.&lt;br /&gt;
&lt;br /&gt;
This is the basic data structure we are going to use. There are many more fields within related to each activity that we could add, but for the moment this will do.&lt;br /&gt;
&lt;br /&gt;
 array(&lt;br /&gt;
  &#039;id&#039;=&amp;gt; new external_value(PARAM_INT,&#039;The id of the activity&#039;),&lt;br /&gt;
  &#039;name&#039; =&amp;gt; new external_value(PARAM_TEXT,&#039;The name of the activity&#039;),&lt;br /&gt;
  &#039;mod&#039; =&amp;gt; new external_value(PARAM_ALPHANUM,&#039;The module that provides this activity.&#039;)&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
This is enough of a structure to return an interesting result. It&#039;s time to move on to the worker function itself.&lt;br /&gt;
&lt;br /&gt;
5. The worker function.&lt;br /&gt;
&lt;br /&gt;
This is where the data gathering is done. The previous two functions mean that we can leave Moodle to do the heavy lifting when it comes time to make and send requests.  The worker function just needs to get the data we are after and return it in a php data structure that matches the template we&#039;ve outlined in the _return function.&lt;br /&gt;
&lt;br /&gt;
     public static function get_course_activities ($courseid) {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
        require_once($CFG-&amp;gt;dirroot . &amp;quot;/course/lib.php&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
        $params = self::validate_parameters(self::get_course_activities_parameters(),&lt;br /&gt;
            array(&#039;courseid&#039; =&amp;gt; $courseid)&lt;br /&gt;
        );&lt;br /&gt;
 &lt;br /&gt;
        //retrieve courses&lt;br /&gt;
        if (!key_exists(&#039;courseid&#039;, $params)) { //Will probably need to chuck a narny.&lt;br /&gt;
            throw new moodle_exception(get_string(&#039;nocourseid&#039;, &#039;webservice&#039;, $exceptionparam));&lt;br /&gt;
        } else {&lt;br /&gt;
            $activities_raw = get_array_of_activities($params[&#039;courseid&#039;]);&lt;br /&gt;
 &lt;br /&gt;
            $activities = array();&lt;br /&gt;
 &lt;br /&gt;
            foreach($activities_raw as $key =&amp;gt; $activity_raw) {&lt;br /&gt;
                $activity = array();&lt;br /&gt;
                $activity[&amp;quot;id&amp;quot;] = $activity_raw-&amp;gt;id;&lt;br /&gt;
                $activity[&amp;quot;name&amp;quot;] = $activity_raw-&amp;gt;name;&lt;br /&gt;
                $activity[&amp;quot;mod&amp;quot;] = $activity_raw-&amp;gt;mod;&lt;br /&gt;
 &lt;br /&gt;
                $activities[] = $activity;&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            return $activities;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
This is everything we need to make the whole web service work, but perhaps we should break it down and look at it.&lt;br /&gt;
&lt;br /&gt;
First some of the basics&lt;br /&gt;
&lt;br /&gt;
        global $CFG;&lt;br /&gt;
        require_once($CFG-&amp;gt;dirroot . &amp;quot;/course/lib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Instead of re-inventing the wheel and working out how collect the data for ourselves we are essentially going to wrap the get_array_of_activities function provided by the course library. It takes care of making the right database calls and putting the information together. It will also mean that the information is returned consistently the same whether you are using the internal call or the external call (web service).&lt;br /&gt;
&lt;br /&gt;
Next we will validate the incoming data. This is where the _parameters method comes in. To validate we call the validate_parameters function that is provided for free by extending the external_api class. We provide to it the _parameters function for the web service being created and the incoming data. In this case in a format to match the top level structure that we defined in _parameters function.&lt;br /&gt;
&lt;br /&gt;
        $params = self::validate_parameters(self::get_course_activities_parameters(),&lt;br /&gt;
            array(&#039;courseid&#039; =&amp;gt; $courseid)&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
From this call we are provided with the $params data structure. This will provide a structure that matches the structure set up in the _parameters function.&lt;br /&gt;
&lt;br /&gt;
        //retrieve courses&lt;br /&gt;
        if (!key_exists(&#039;courseid&#039;, $params)) { //Will probably need to chuck a narny.&lt;br /&gt;
            throw new moodle_exception(get_string(&#039;nocourseid&#039;, &#039;webservice&#039;, $exceptionparam));&lt;br /&gt;
        } else {&lt;br /&gt;
          //Here we will place the work code that provides the activity data.&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
If we don&#039;t have a courseid value we will instead return with a moodle_exception. If everything is fine proceed to to collecting the activity information. Inside the if statement we add this:&lt;br /&gt;
&lt;br /&gt;
            $activities_raw = get_array_of_activities($params[&#039;courseid&#039;]);&lt;br /&gt;
 &lt;br /&gt;
            $activities = array();&lt;br /&gt;
 &lt;br /&gt;
            foreach($activities_raw as $key =&amp;gt; $activity_raw) {&lt;br /&gt;
                $activity = array();&lt;br /&gt;
                $activity[&amp;quot;id&amp;quot;] = $activity_raw-&amp;gt;id;&lt;br /&gt;
                $activity[&amp;quot;name&amp;quot;] = $activity_raw-&amp;gt;name;&lt;br /&gt;
                $activity[&amp;quot;mod&amp;quot;] = $activity_raw-&amp;gt;mod;&lt;br /&gt;
 &lt;br /&gt;
                $activities[] = $activity;&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            return $activities;&lt;br /&gt;
&lt;br /&gt;
In essence this code calls the course function get_array_of_activities and then processes the result. The structure to be built is an array of named arrays. To do this we create the $activities array and then loop through the object we received back. For each entry we create another array (convenience of php) and add named entries to match the fields in the _returns function. In this case we add the &#039;id&#039;, &#039;name&#039; and &#039;mod&#039; fields. &lt;br /&gt;
&lt;br /&gt;
Once done we then append the $activity array to the list of others we are collecting and final return them.&lt;br /&gt;
&lt;br /&gt;
At this point the web-service is ready to go except for the database entry that will tell moodle that we have a new web service available and where to find it.&lt;br /&gt;
&lt;br /&gt;
=== Adding the database entry ===&lt;br /&gt;
&lt;br /&gt;
For now we will do this the hard (and not good) way. &lt;br /&gt;
&lt;br /&gt;
Moodle web-services are described in the external_functions (mdl_external_functions) table.&lt;br /&gt;
&lt;br /&gt;
The table has six fields that we need to fill in:&lt;br /&gt;
* name - This is the name of the service and the way it will be referred to by moodle. Consider it the public name&lt;br /&gt;
* classname - This is the name of the class that provides this method. In this case moodle_course_external&lt;br /&gt;
* methodname - The name of the method: In this case get_course_activities. Moodle will work out the _returns and _parameters&lt;br /&gt;
* classpath - The name of the file that the class (referred to in classname) can be found in. The path is relative to the moodle root. In this case: &#039;course/externallib.php&#039;. externallib.php is the default for these services and all of the core services are found here so stick with it.&lt;br /&gt;
* component - all the core services belong to &#039;moodle&#039;. This (I&#039;m currently guessing) refers to the component that is providing the services. I.E. If you&#039;re not contributing to core avoid using &#039;moodle&#039; here.&lt;br /&gt;
* capabilities - These are the capabilities users will require to successfully use this service.&lt;br /&gt;
&lt;br /&gt;
(NB: I&#039;m sure there has to be a better way than to add the db entries directly)&lt;br /&gt;
&lt;br /&gt;
As a result we get the following query for this service:&lt;br /&gt;
&lt;br /&gt;
 insert into mdl_external_functions (name,classname,methodname,classpath,component,capabilities) values&lt;br /&gt;
 (&#039;moodle_course_get_course_activities&#039;,&#039;moodle_course_external&#039;,&#039;get_course_activities&#039;,&lt;br /&gt;
 &#039;course/externallib.php&#039;,&#039;moodle&#039;,&#039;moodle/course:view,moodle/course:viewhiddencourses&#039;)&lt;br /&gt;
&lt;br /&gt;
And from here we are done. You can now find and configure the new web-service through the admin area.&lt;br /&gt;
&lt;br /&gt;
== Of course there is testing ==&lt;br /&gt;
&lt;br /&gt;
It would appear that the web-service tests in Moodle aren&#039;t able to read and test new ones without code additions. In which case try this. Fill in the blanks and run this in a php environment.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 &lt;br /&gt;
    error_reporting(E_ALL);&lt;br /&gt;
    $s = new SoapClient(&amp;quot;http://add-your-moodle-url/webservice/soap/server.php?wstoken=add-your-ws-token&amp;amp;wsdl=1&amp;quot;);&lt;br /&gt;
    var_dump($s-&amp;gt;moodle_course_get_course_activities(--add a course id--));&lt;br /&gt;
 &lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Data Structure Descriptors ==&lt;br /&gt;
&lt;br /&gt;
In order to keep a little of the technical stuff out of the tutorial and provide an overview of the data structures:&lt;br /&gt;
&lt;br /&gt;
=== external_single_structure ===&lt;br /&gt;
&lt;br /&gt;
This method translates to a named array or hash with a subset of elements that provide the requested data.&lt;br /&gt;
&lt;br /&gt;
Because of this you can imagine this to be the equivalent of a named array, hash or object wrapper.&lt;br /&gt;
&lt;br /&gt;
i.e. external_single_structure = hash&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== external_multiple_structure ===&lt;br /&gt;
&lt;br /&gt;
external_multiple_structure = array&lt;br /&gt;
&lt;br /&gt;
=== external_value ===&lt;br /&gt;
&lt;br /&gt;
external_value object is used to specify a data field. It requires two values, a type constant (see below) and a description string.&lt;br /&gt;
&lt;br /&gt;
==== Available type constants ====&lt;br /&gt;
&lt;br /&gt;
* PARAM_INT : specifies an integer data type.&lt;br /&gt;
* PARAM_TEXT : (description required).&lt;br /&gt;
* PARAM_RAW : (description required).&lt;/div&gt;</summary>
		<author><name>Ddelrio1986</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=XMLDB_introduction&amp;diff=6268</id>
		<title>XMLDB introduction</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=XMLDB_introduction&amp;diff=6268"/>
		<updated>2007-04-30T14:48:15Z</updated>

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