<?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=Aolley</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=Aolley"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Aolley"/>
	<updated>2026-06-24T20:07:28Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_renderers&amp;diff=48433</id>
		<title>Output renderers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_renderers&amp;diff=48433"/>
		<updated>2015-08-11T01:02:52Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Creating a Renderable &amp;quot;widget&amp;quot; in your theme */ Renderable gets passed to the render call&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Output renderers&lt;br /&gt;
|state = Implemented&lt;br /&gt;
|tracker = MDL-21235&lt;br /&gt;
|discussion = n/a&lt;br /&gt;
|assignee = [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]] + [[User:David Mudrak|David Mudrak]] + feedback and ideas from other developers&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
* stable API&lt;br /&gt;
* easy to use&lt;br /&gt;
* easy to customise via themes&lt;br /&gt;
&lt;br /&gt;
== Renderers ==&lt;br /&gt;
&lt;br /&gt;
Output renderer is a class with collection of methods that handle rendering of visual aspects of Moodle pages, emails, html export, etc. In Moodle 1.9, general output related functions were located in weblib.php and modules stored rendering code in lib.php, locallib.php, view.php, etc. Output renderer instances are obtained through moodle_page::get_renderer($component, $subtype = null, $target = null) method.&lt;br /&gt;
&lt;br /&gt;
The general renderer class naming convention is:&lt;br /&gt;
 {theme name}_{plugin type}_{plugin_name}_{subtype}_renderer_{target}&lt;br /&gt;
&lt;br /&gt;
or (if using namespaces)&lt;br /&gt;
&lt;br /&gt;
 \{plugin type}_{plugin name}\output\{subtype}_renderer_{target} (standard plugin renderer)&lt;br /&gt;
&lt;br /&gt;
 \theme_{theme name}\output\{plugin type}_{plugin name}\{subtype}_renderer_{target} (plugin renderer overridden in a theme)&lt;br /&gt;
&lt;br /&gt;
where theme name prefix, subtype infix and target suffix are optional. Examples of renderer class name are core_renderer, mytheme_core_renderer, mod_workshop_renderer, mod_forum_renderer_cli, \tool_templatelibrary\output\renderer etc.&lt;br /&gt;
&lt;br /&gt;
; Renderer subtype : When get_renderer() is called, $subtype parameter can be provided to obtain a different renderer. Renderer subtypes are used mainly for core subsystems, but it is also possible to use them in modules.&lt;br /&gt;
&lt;br /&gt;
; Renderer targets : In most cases, we are rendering page output for web browsers. Sometimes we need to generate different output for command line scripts, email messages, etc. When get_renderer() is called, $target parameter can be provided to obtain a different renderer. The list of targets will be part of the specification, individual plugins should not invent new rendering targets.&lt;br /&gt;
&lt;br /&gt;
: note that both $subtype and $target works similarly - they just influence the name of the class to be returned by get_renderer(). But there is semantic difference and we will probably have the list of allowed targets limited (defaults to html).&lt;br /&gt;
&lt;br /&gt;
== Overall picture ==&lt;br /&gt;
&lt;br /&gt;
The following UML diagram describes the main classes involved in HTML output rendering and their relationships.&lt;br /&gt;
&lt;br /&gt;
[[Image:uml_output_renderers.png|800px|left]] [[Media:uml_output_renderers.dia|(dia source)]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== renderer_base ===&lt;br /&gt;
&lt;br /&gt;
Abstract class every other renderer must extend. Renderer base implements basic methods and support for renderer dispatching.&lt;br /&gt;
&lt;br /&gt;
=== core_renderer ===&lt;br /&gt;
&lt;br /&gt;
Current core_renderer is available through the global $OUTPUT variable. This global should not be used in lower level APIs - only in the main scripts like view.php. When you want to start to print something, you will probably call&lt;br /&gt;
 echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
in your view.php or similar script. To print a page footer and terminate your PHP script, you will call&lt;br /&gt;
 echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
 die();&lt;br /&gt;
&lt;br /&gt;
Beside these page header and footer related things, core_renderer knows how to display&lt;br /&gt;
# boxes and containers - basically &amp;amp;lt;div&amp;amp;gt; elements&lt;br /&gt;
# general widgets - headings, single buttons, selection forms, arrows in the breadcrumb navigation, language selection popup, user login info etc.&lt;br /&gt;
# error messages, notifications&lt;br /&gt;
# blocks&lt;br /&gt;
&lt;br /&gt;
=== method render() and interface renderable ===&lt;br /&gt;
&lt;br /&gt;
Various widgets (headings, buttons etc.) and other content blocks (submissions, forum posts etc.) are represented as classes. In most cases, they will look like a simple object with just some properties and a constructor to set the most common ones. Core renderer implements protected methods to render these widgets. These widget rendering methods are called render_something() where &#039;&#039;something&#039;&#039; is the name of the widget. Their first parameter must be an instance of &#039;&#039;something&#039;&#039; class that implements interface &#039;&#039;renderable&#039;&#039;. These methods can be overridden by themes.&lt;br /&gt;
&lt;br /&gt;
Public method to render a widget is called render(). It accepts the only parameter which must be an instance of a class implementing &#039;&#039;renderable&#039;&#039; interface. It uses the class name of the widget passed in as parameter to find the corresponding protected rendering method.&lt;br /&gt;
&lt;br /&gt;
Implementation of renderer_base::render() (inherited by all renderers)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class renderer_base {&lt;br /&gt;
    // ...&lt;br /&gt;
    public function render(renderable $widget) {&lt;br /&gt;
        $rendermethod = &#039;render_&#039;.get_class($widget);&lt;br /&gt;
        if (method_exists($this, $rendermethod)) {&lt;br /&gt;
            return $this-&amp;gt;$rendermethod($widget);&lt;br /&gt;
        }&lt;br /&gt;
        throw new coding_exception(&#039;Can not render widget, renderer method (&#039;.$rendermethod.&#039;) not found.&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some widgets, a helper method may be implemented to instantiate the widget and render it in the background. Such helper methods have the same name as the widget class and accepts parameters needed to create the widget instance. Themes should not override helper methods because their usage is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; User avatar rendering involves following methods and classes:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class core_renderer extends renderer_base {&lt;br /&gt;
    // ...&lt;br /&gt;
    protected function render_user_picture(user_picture $userpicture) {&lt;br /&gt;
        // returns HTML code to be echoed for displaying the user avatar&lt;br /&gt;
    }&lt;br /&gt;
    public function user_picture(stdclass $userrecord, array $options=null) {&lt;br /&gt;
        // helper method that constructs $user_image widget and calls $this-&amp;gt;render()&lt;br /&gt;
        $picture = new user_picture($userrecord, $options);&lt;br /&gt;
        return $this-&amp;gt;render($picture);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
class user_picture implements renderable {&lt;br /&gt;
    public $userrecord;&lt;br /&gt;
    public $courseid = 0;&lt;br /&gt;
    public $link = true;&lt;br /&gt;
&lt;br /&gt;
    public function __construct(stdclass $userrecord, array $options=null) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are two ways how a developer can render the user picture. Either using a one-line style:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(...));&lt;br /&gt;
echo $OUTPUT-&amp;gt;user_picture($user, array(&#039;courseid&#039; =&amp;gt; $courseid, &#039;link&#039; =&amp;gt; true));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or an explicit stye:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(...));&lt;br /&gt;
$avatar = new user_picture($user);&lt;br /&gt;
$avatar-&amp;gt;courseid = $courseid;&lt;br /&gt;
$avatar-&amp;gt;link = true;&lt;br /&gt;
echo $OUTPUT-&amp;gt;render($avatar);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point is that the first style is usually one line only, it is also possible to have multiple helpers with different parameters. The second style allows more options without cluttering the simple API with tons of optional method parameters.&lt;br /&gt;
&lt;br /&gt;
Plugins can also use renderable objects and define render_something() functions in plugin renderers.&lt;br /&gt;
&lt;br /&gt;
=== core_renderer_cli ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;_cli&#039;&#039; suffix indicates this is a core renderer for CLI rendering target (CLI scripts). For example headings are using &#039;&#039;&#039;=&amp;gt;&#039;&#039;&#039; instead if H2 html tag.&lt;br /&gt;
&lt;br /&gt;
== Core subsystem renderers ==&lt;br /&gt;
&lt;br /&gt;
== Plugin renderers ==&lt;br /&gt;
&lt;br /&gt;
Plugin renderers are stored in renderer.php file in the same folder as the lib.php file of each plugin. They all extend plugin_renderer_base method.&lt;br /&gt;
&lt;br /&gt;
=== plugin_renderer_base ===&lt;br /&gt;
&lt;br /&gt;
An important thing about this class is that it keeps a reference to an instance of (typically) core_renderer which is used as an underlying renderer. This reference is kept in protected $output member variable. So, there is no more $OUTPUT in plugin renderers. They all use $this-&amp;gt;output-&amp;gt;something() to render the output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; Workshop module defines mod_workshop_renderer class in mod/workshop/renderer.php file. The renderer defines a method to display a student submission.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// in renderer.php:&lt;br /&gt;
class workshop_submission implements renderable {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(stdclass $submission, $anonymous = false, array $attachments = null) {&lt;br /&gt;
        // here the widget is prepared and all necessary logic is performed&lt;br /&gt;
        if ($anonymous) {&lt;br /&gt;
            $this-&amp;gt;authorname = get_string(&#039;anonymousauthor&#039;, &#039;workshop&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $this-&amp;gt;authorname = fullname(...);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
class mod_workshop_renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
    protected function render_workshop_submission(workshop_submission $submission) {&lt;br /&gt;
        $out  = $this-&amp;gt;output-&amp;gt;heading(format_string($submission-&amp;gt;title), 2);&lt;br /&gt;
        $out .= $this-&amp;gt;output-&amp;gt;container(format_string($submission-&amp;gt;authorname), &#039;author&#039;);&lt;br /&gt;
        $out .= $this-&amp;gt;output-&amp;gt;container(format_text($submission-&amp;gt;content, FORMAT_HTML), &#039;content&#039;);&lt;br /&gt;
        return $this-&amp;gt;output-&amp;gt;container($out, &#039;submission&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// in view.php&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;mod_workshop&#039;);&lt;br /&gt;
$submissionrecord = get_record(&#039;workshop_submissions&#039;, array(...));&lt;br /&gt;
$submissionwidget = new workshop_submission($submissionrecord, false);&lt;br /&gt;
echo $output-&amp;gt;header();&lt;br /&gt;
echo $output-&amp;gt;render($submissionwidget);&lt;br /&gt;
echo $output-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that $output-&amp;gt;header() and $output-&amp;gt;footer() are not defined in mod_workshop_renderer. Plugin renderers are able to forward calls to the underlying renderer automatically. So, in view.php, there could be echo $OUTPUT-&amp;gt;header(); which would call the same method. We prefer the way above because of consistency - there is the only one $output instance used instead of two $OUTPUT and $wsoutput.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING: get_renderer() should typically be the last output related call you make before displaying your page&#039;s header.&#039;&#039;&#039; get_renderer() forces the page layout to &#039;base&#039; if it has not already been set and this will almost certainly cause your page to display incorrectly (e.g. no blocks).&lt;br /&gt;
&lt;br /&gt;
Note that as of Moodle 2.9, the render method could be rewritten to use a template. See [[Templates]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Bootstrap renderer ==&lt;br /&gt;
&lt;br /&gt;
Bootstrap renderer is used as a temporary $OUTPUT before the full initialisation of standard core renderer.&lt;br /&gt;
&lt;br /&gt;
== Theme customisations ==&lt;br /&gt;
&lt;br /&gt;
=== Theme renderers ===&lt;br /&gt;
&lt;br /&gt;
Theme renderers are stored in renderers.php file in theme folder (or autoloaded from the classes folder). The actual overriding of renderers is the responsibility of renderer_factory classes which may be selected in theme config.php.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Renderable &amp;quot;widget&amp;quot; in your theme ===&lt;br /&gt;
&lt;br /&gt;
To create a renderable &amp;quot;widget&amp;quot; that could be used in multiple places in your theme (e.g. on the front page, in an overriden renderer for mod_assign etc.)&lt;br /&gt;
Create a renderable and renderer in the following folder:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/theme/mytheme/output/mywidget/rendererable.php&lt;br /&gt;
theme/mytheme/output/mywidget/renderer.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mywidgetrenderable  = new \theme_mytheme\output\mywidget\renderable($params);&lt;br /&gt;
$mywidgetrenderer = $this-&amp;gt;page-&amp;gt;get_renderer(&#039;theme_mytheme&#039;,&#039;mywidget&#039;); // Or $PAGE-&amp;gt;get_renderer depending on context&lt;br /&gt;
$mywidget = $mywidgetrenderer-&amp;gt;render($mywidgetrenderable);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
there is a good example of this in moodle core -&amp;gt; /admin/tool/monitor&lt;br /&gt;
&lt;br /&gt;
== Low level HTML output ==&lt;br /&gt;
&lt;br /&gt;
Low level html markup is created via html_renderer class.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Theme changes]]&lt;br /&gt;
* Using Moodle [http://moodle.org/mod/forum/discuss.php?d=177535 Totally confused by output renderers...] forum discussion&lt;br /&gt;
&lt;br /&gt;
[[Category:Themes]]&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34862</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34862"/>
		<updated>2012-08-16T00:29:48Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
User documentation here: https://docs.moodle.org/22/en/report/engagement/index&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/engagement/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/engagement/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;engagementindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;engagementindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;engagementindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/engagementindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;engagement|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
thresholds_form.php :&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class engagementindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;engagementindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;engagementindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicator Renderer==&lt;br /&gt;
&lt;br /&gt;
The user report view which lists details from each indicator is defined in an indicators renderer file. If the user_report function is not overridden, the default renderer will simply display the risk score given by that indicator.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class engagementindicator_random_renderer extends engagementindicator_renderer {&lt;br /&gt;
    public function user_report($data) {&lt;br /&gt;
        $html = &#039;&#039;;&lt;br /&gt;
        foreach ($data-&amp;gt;info as $i) {&lt;br /&gt;
            $html .= html_writer::start_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, $i-&amp;gt;title);&lt;br /&gt;
            $html .= html_writer::end_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
            $html .= $this-&amp;gt;output-&amp;gt;help_icon(&#039;localrisk&#039;, &#039;engagementindicator_random&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, &#039;Local risk: &#039; . $i-&amp;gt;localrisk);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For the above example to work, the random indicator would need to be returning valid data in the...&amp;lt;TODO&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
User documentation: https://docs.moodle.org/22/en/report/engagement/index&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34861</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34861"/>
		<updated>2012-08-16T00:28:47Z</updated>

		<summary type="html">&lt;p&gt;Aolley: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
User documentation here: https://docs.moodle.org/22/en/report/engagement/index&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/engagement/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/engagement/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;engagementindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;engagementindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;engagementindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/engagementindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;engagement|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
thresholds_form.php :&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class engagementindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;engagementindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;engagementindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicator Renderer==&lt;br /&gt;
&lt;br /&gt;
The user report view which lists details from each indicator is defined in an indicators renderer file. If the user_report function is not overridden, the default renderer will simply display the risk score given by that indicator.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class engagementindicator_random_renderer extends engagementindicator_renderer {&lt;br /&gt;
    public function user_report($data) {&lt;br /&gt;
        $html = &#039;&#039;;&lt;br /&gt;
        foreach ($data-&amp;gt;info as $i) {&lt;br /&gt;
            $html .= html_writer::start_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, $i-&amp;gt;title);&lt;br /&gt;
            $html .= html_writer::end_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
            $html .= $this-&amp;gt;output-&amp;gt;help_icon(&#039;localrisk&#039;, &#039;engagementindicator_random&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, &#039;Local risk: &#039; . $i-&amp;gt;localrisk);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For the above example to work, the random indicator would need to be returning valid data in the...&amp;lt;TODO&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
User documentation: https://docs.moodle.org/22/en/report/analytics/index&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34746</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34746"/>
		<updated>2012-08-13T07:27:43Z</updated>

		<summary type="html">&lt;p&gt;Aolley: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
User documentation here: https://docs.moodle.org/22/en/report/analytics/index&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
thresholds_form.php :&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class analyticsindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicator Renderer==&lt;br /&gt;
&lt;br /&gt;
The user report view which lists details from each indicator is defined in an indicators renderer file. If the user_report function is not overridden, the default renderer will simply display the risk score given by that indicator.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class analyticsindicator_random_renderer extends analyticsindicator_renderer {&lt;br /&gt;
    public function user_report($data) {&lt;br /&gt;
        $html = &#039;&#039;;&lt;br /&gt;
        foreach ($data-&amp;gt;info as $i) {&lt;br /&gt;
            $html .= html_writer::start_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, $i-&amp;gt;title);&lt;br /&gt;
            $html .= html_writer::end_tag(&#039;strong&#039;);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
            $html .= $this-&amp;gt;output-&amp;gt;help_icon(&#039;localrisk&#039;, &#039;analyticsindicator_random&#039;);&lt;br /&gt;
            $html .= html_writer::tag(&#039;span&#039;, &#039;Local risk: &#039; . $i-&amp;gt;localrisk);&lt;br /&gt;
            $html .= html_writer::empty_tag(&#039;br&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return $html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
For the above example to work, the random indicator would need to be returning valid data in the...&amp;lt;TODO&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
User documentation: https://docs.moodle.org/22/en/report/analytics/index&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34737</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34737"/>
		<updated>2012-08-13T06:54:56Z</updated>

		<summary type="html">&lt;p&gt;Aolley: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
User documentation here: https://docs.moodle.org/22/en/report/analytics/index&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
thresholds_form.php :&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class analyticsindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34719</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34719"/>
		<updated>2012-08-13T05:33:44Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
thresholds_form.php :&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class analyticsindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34718</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34718"/>
		<updated>2012-08-13T05:33:02Z</updated>

		<summary type="html">&lt;p&gt;Aolley: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==Indicator Thresholds==&lt;br /&gt;
&lt;br /&gt;
Thresholds and other settings that get applied in the calculate_risks stage can be added to an indicator in the &amp;lt;tt&amp;gt;thresholds_form.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The settings added to the &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; function should have a name of the format: &amp;quot;&amp;lt;indicatorname&amp;gt;_&amp;lt;setting&amp;gt;&amp;quot;. i.e. for the setting &amp;quot;e_loginsperweek&amp;quot; setting of the &amp;quot;login&amp;quot; indicator, the name would be &amp;quot;login_e_loginsperweek&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class analyticsindicator_random_thresholds_form {&lt;br /&gt;
    public function definition_inner(&amp;amp;$mform) {&lt;br /&gt;
        $defaults = indicator_login::get_defaults();&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_min&#039;, get_string(&#039;minimum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_min&amp;quot;, $defaults[&#039;min&#039;]);&lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;random_max&#039;, get_string(&#039;maximum&#039;, &#039;analyticsindicator_random&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&amp;quot;random_max&amp;quot;, $defaults[&#039;max&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34717</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34717"/>
		<updated>2012-08-13T05:23:58Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Main info */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
Caching of raw data from different indicator plugins is automatically handled by the base indicator class so developers of new indicators don&#039;t need to worry about more expensive queries.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34716</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34716"/>
		<updated>2012-08-13T05:21:19Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get_rawdata&amp;lt;/tt&amp;gt; function is intended to do the heavy lifting part of the indicator. It&#039;ll do the lookups into the database to find out the raw data for the courses users. For example, this collects the counts of read/new/total/replied posts in the forum indicator. This function is called on by the parent class and is put into a cache. The cache has a configurable lifetime set in Site administration / ► Plugins / ► Activity modules / ► Engagement analytics. The setting is &amp;lt;tt&amp;gt;analytics|cachettl&amp;lt;/tt&amp;gt; which defaults to 5 minutes. Larger sites may want to consider setting this to a larger number depending on the set of indicators they&#039;re using.&lt;br /&gt;
&lt;br /&gt;
The next step in the workflow takes that raw data (which comes from get_cache() unless there&#039;s no valid cache entry, which means get_rawdata is called for the data instead) and applies the course specific settings for that indicator. This is done in the &amp;lt;tt&amp;gt;calculate_risks&amp;lt;/tt&amp;gt; function. This function will apply the settings set in the report settings page. This allows teachers to update the weightings / thresholds of indicators and see the new risk values without having to refetch raw data every time.&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34709</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34709"/>
		<updated>2012-08-13T03:09:36Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Except for the functions mentioned below, the rest of the ones mentioned above are not generally intended to be overridden in the indicators themselves.&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34708</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34708"/>
		<updated>2012-08-13T03:07:56Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* Main info */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
The indicator&#039;s used by this plugin have been designed as sub-plugins to allow (and encourage) other developers to create their own indicators. Indicators could be developed to report on a wide range of things inside Moodle or even collect data from external systems to report on if desired.&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34707</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34707"/>
		<updated>2012-08-13T03:03:21Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* indicator_random */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_rawdata($startdate, $enddate) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $rawdata = array();&lt;br /&gt;
        $someusers = get_enrolled_users($this-&amp;gt;context);&lt;br /&gt;
        foreach ($someusers as $user) {&lt;br /&gt;
            $rawdata[$user-&amp;gt;id] = mt_rand(0,100);&lt;br /&gt;
        }&lt;br /&gt;
        return $rawdata;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function calculate_risks(array $userids) {&lt;br /&gt;
        $risks = array();&lt;br /&gt;
        foreach ($userids as $userid) {&lt;br /&gt;
            if (!isset($this-&amp;gt;rawdata[$userid])) {&lt;br /&gt;
                $risk = new stdClass();&lt;br /&gt;
                $risk-&amp;gt;risk = 0;&lt;br /&gt;
                $risk-&amp;gt;info = &#039;No risk, user had no data collected.&#039;;&lt;br /&gt;
                $risks[$userid] = $risk;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            $risk = new stdClass();&lt;br /&gt;
            $value = $this-&amp;gt;rawdata[$userid];&lt;br /&gt;
            if ($value &amp;gt; $this-&amp;gt;config[&#039;max&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;max&#039;];&lt;br /&gt;
            } else if ($value &amp;lt; $this-&amp;gt;config[&#039;min&#039;]) {&lt;br /&gt;
                $value = $this-&amp;gt;config[&#039;min&#039;];&lt;br /&gt;
            }&lt;br /&gt;
            $risk-&amp;gt;risk = $value;&lt;br /&gt;
            $risk-&amp;gt;info = &#039;Random risk calcualted.&#039;;&lt;br /&gt;
            $risks[$userid] = $risk;&lt;br /&gt;
        }&lt;br /&gt;
        return $risks;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function load_config() {&lt;br /&gt;
        parent::load_config();&lt;br /&gt;
        $defaults = $this-&amp;gt;get_defaults();&lt;br /&gt;
        foreach ($defaults as $setting =&amp;gt; $value) {&lt;br /&gt;
            if (!isset($this-&amp;gt;config[$setting])) {&lt;br /&gt;
                $this-&amp;gt;config[$setting] = $value;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        $defaults = array();&lt;br /&gt;
        $defaults[&#039;min&#039;] = 5;&lt;br /&gt;
        $defaults[&#039;max&#039;] = 20;&lt;br /&gt;
        return $defaults;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34706</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34706"/>
		<updated>2012-08-13T01:13:12Z</updated>

		<summary type="html">&lt;p&gt;Aolley: Function listing for indicators&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
The indicator base class defines the following functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function get_risk($userid, $courseid, $startdate = null, $enddate = null);&lt;br /&gt;
public function get_course_risks($startdate = null, $enddate = null);&lt;br /&gt;
private function get_risk_for_users($userids, $startdate, $enddate);&lt;br /&gt;
final private function get_cache();&lt;br /&gt;
final private function set_cache();&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
public function get_name();&lt;br /&gt;
protected function load_config();&lt;br /&gt;
public function save_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the development of any new indicator, the functions you &#039;&#039;&#039;must&#039;&#039;&#039; implement are the abstracted ones:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
abstract protected function get_rawdata($startdate, $enddate);&lt;br /&gt;
abstract protected function calculate_risks(array $userids);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have any settings (and most indicators probably will), you&#039;ll probably need:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function load_config();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Which can be used to setup any default values you need for when a user hasn&#039;t input any on their own.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_risk_for_users($userids, $courseid, $startdate, $enddate) {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // TODO: Complete class definition.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34705</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34705"/>
		<updated>2012-08-13T01:05:34Z</updated>

		<summary type="html">&lt;p&gt;Aolley: /* The indicator class */ Add file list for indicators&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
==Indicator==&lt;br /&gt;
&lt;br /&gt;
===File Layout===&lt;br /&gt;
Indicators live in a folder in &amp;lt;tt&amp;gt;mod/analytics/indicator&amp;lt;/tt&amp;gt;. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the &amp;lt;tt&amp;gt;mod/analytics/indicator/myind&amp;lt;/tt&amp;gt; folder we would have:&lt;br /&gt;
&lt;br /&gt;
; indicator.class.php : Defines the &amp;lt;tt&amp;gt;indicator_myind&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;indicator&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; renderer.php : This contains the definition of the &amp;lt;tt&amp;gt;analyticsindicator_myind_renderer&amp;lt;/tt&amp;gt; class, which should extend the &amp;lt;tt&amp;gt;analyticsindicator_renderer&amp;lt;/tt&amp;gt; base class.&lt;br /&gt;
; thresholds_form.php : Defines the &amp;lt;tt&amp;gt;analyticsindicator_myind_thresholds_form&amp;lt;/tt&amp;gt; which contains a function &amp;lt;tt&amp;gt;definition_inner&amp;lt;/tt&amp;gt; for including on the report settings page.&lt;br /&gt;
; lang/en/analyticsindicator_myind.php : English language strings for this indicator. You can, of course, include other languages too. The language file must define at least the string giving the indicator a name, for example &amp;lt;tt&amp;gt;$string[&#039;pluginname&#039;] = &#039;My Indicator&#039;;&amp;lt;/tt&amp;gt;&lt;br /&gt;
; db/install.xml, db/upgrade.php : For creating any database tables required, [[Installing_and_upgrading_plugin_database_tables|as normal]]. See [[#Database_tables]] below.&lt;br /&gt;
; db/access.php : Defines any capabilities required by this question type. This is very rarely needed.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_risk_for_users($userids, $courseid, $startdate, $enddate) {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // TODO: Complete class definition.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34609</id>
		<title>report/analytics/api</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=report/analytics/api&amp;diff=34609"/>
		<updated>2012-08-01T03:28:47Z</updated>

		<summary type="html">&lt;p&gt;Aolley: Bare bones entry&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
== The indicator class ==&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_risk_for_users($userids, $courseid, $startdate, $enddate) {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // TODO: Complete class definition.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Data_manipulation_API&amp;diff=34608</id>
		<title>Data manipulation API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Data_manipulation_API&amp;diff=34608"/>
		<updated>2012-08-01T03:27:58Z</updated>

		<summary type="html">&lt;p&gt;Aolley: Undo revision 34607 by Aolley (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}This page describes the functions available to access data in the Moodle database. You should &#039;&#039;&#039;exclusively&#039;&#039;&#039; use these functions in order to retrieve or modify database content because these functions provide a high level of abstraction and guarantee that your database manipulation will work against different RDBMSes.&lt;br /&gt;
&lt;br /&gt;
Where possible, tricks and examples will be documented here in order to make developers&#039; lives a bit easier. Of course, feel free to clarify, complete and add more information to  this documentation. It will be welcome, absolutely!&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important note:&#039;&#039;&#039; All the functions shown on this page are for use in &#039;&#039;&#039;Moodle 2.0 upwards&#039;&#039;&#039;, where we changed the [[DB layer 2.0|DB layer]] to support some new features. If you need information for previous Moodle version, take a look to the [[DML functions - pre 2.0|DML functions - pre 2.0]] page. For a detailed reference of changes, see the [[DB layer 2.0 migration docs|migration docs]].&lt;br /&gt;
&lt;br /&gt;
* All the function calls on this page are public methods of the $DB global object, so you&#039;ll need to &amp;quot;import&amp;quot; it within your functions (not needed in global scripts) with one simple:&lt;br /&gt;
&amp;lt;code php&amp;gt;global $DB;&amp;lt;/code&amp;gt;&lt;br /&gt;
* The $DB global object is an instance of the moodle_database class, which is defined in [http://cvs.moodle.org/moodle/lib/dml/moodle_database.php?view=markup moodle_database.php]&lt;br /&gt;
* All the $table parameters in the functions are meant to be the table name &#039;&#039;without&#039;&#039; prefixes.&lt;br /&gt;
&amp;lt;code php&amp;gt;$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(&#039;id&#039;=&amp;gt;&#039;1&#039;);&amp;lt;/code&amp;gt;&lt;br /&gt;
* When using the xxx_sql() functions, table names must be enclosed between curly braces.&lt;br /&gt;
&amp;lt;code php&amp;gt;$user = $DB-&amp;gt;get_record_sql(&#039;SELECT * FROM {user} WHERE id = ?&#039;, array(1));&amp;lt;/code&amp;gt;&lt;br /&gt;
* All the $conditions parameters in the functions are arrays of fieldname=&amp;gt;fieldvalue elements.&lt;br /&gt;
&amp;lt;code php&amp;gt;$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(&#039;firstname&#039;=&amp;gt;&#039;Martin&#039;, &#039;lastname&#039;=&amp;gt;&#039;Dougiamas&#039;));&amp;lt;/code&amp;gt;&lt;br /&gt;
* All the $params parameters in the functions are arrays of values used to fill placeholders in SQL statements. Both the question mark and named placeholders can be used. Note that named params &#039;&#039;&#039;must be unique&#039;&#039;&#039; even if the value passed is the same.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// Question mark placeholders:&lt;br /&gt;
   $DB-&amp;gt;get_record_sql(&#039;SELECT * FROM {user} WHERE firstname = ? AND lastname = ?&#039;, &lt;br /&gt;
                       array(&#039;Martin&#039;, &#039;Dougiamas&#039;));&lt;br /&gt;
&lt;br /&gt;
/// Named placeholders:&lt;br /&gt;
   $DB-&amp;gt;get_record_sql(&#039;SELECT * FROM {user} WHERE firstname = :firstname AND lastname = :lastname&#039;,&lt;br /&gt;
                       array(&#039;firstname&#039;=&amp;gt;&#039;Martin&#039;, &#039;lastname&#039;=&amp;gt;&#039;Dougiamas&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The functions ==&lt;br /&gt;
&lt;br /&gt;
===Getting a single record===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_record($table, array $conditions, $fields=&#039;*&#039;, $strictness=IGNORE_MISSING) &lt;br /&gt;
  /// Get a single database record as an object where all the given conditions met.&lt;br /&gt;
  /// @param int $strictness IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found;&lt;br /&gt;
  ///                        IGNORE_MULTIPLE means return first, ignore multiple records found(not recommended);&lt;br /&gt;
  ///                        MUST_EXIST means throw exception if no record or multiple records found&lt;br /&gt;
o $DB-&amp;gt;get_record_select($table, $select, array $params=null, $fields=&#039;*&#039;, $strictness=IGNORE_MISSING)&lt;br /&gt;
  /// Get a single database record as an object which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_record_sql($sql, array $params=null, $strictness=IGNORE_MISSING)&lt;br /&gt;
  /// Get a single database record as an object using a SQL statement.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Getting an hashed array of records===&lt;br /&gt;
Each of the following methods return an array of objects. The array is indexed by the first column of the fields returned by the query. Thus to assure consistent data, it appears to be best practice to ensure that your query include an &amp;quot;id column&amp;quot; as the first field. (When developing custom tables, be sure to make id your first column for this reason!)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_records($table, array $conditions=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0) &lt;br /&gt;
  /// Get a number of records as an array of objects where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;get_records_select($table, $select, array $params=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0) &lt;br /&gt;
  /// Get a number of records as an array of objects which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0)&lt;br /&gt;
  /// Get a number of records as an array of objects using a SQL statement.&lt;br /&gt;
o $DB-&amp;gt;get_records_list($table, $field, array $values, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=&#039;&#039;, $limitnum=&#039;&#039;) &lt;br /&gt;
  /// Get a number of records as an array of objects where one field match one list of values.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Getting an &lt;br /&gt;
The following methods return data as key/value pairs in an associative array.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_records_menu($table, array $conditions=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0) &lt;br /&gt;
  /// Get the first two columns from a number of records as an associative array where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;get_records_select_menu($table, $select, array $params=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0)&lt;br /&gt;
  /// Get the first two columns from a number of records as an associative array which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_records_sql_menu($sql, array $params=null, $limitfrom=0, $limitnum=0)&lt;br /&gt;
  /// Get the first two columns from a number of records as an associative array using a SQL statement.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Seeing how many records match a given criteria===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;count_records($table, array $conditions=null) &lt;br /&gt;
  /// Count the records in a table where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;count_records_select($table, $select, array $params=null, $countitem=&amp;quot;COUNT(&#039;x&#039;)&amp;quot;) &lt;br /&gt;
  /// Count the records in a table which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;count_records_sql($sql, array $params=null) &lt;br /&gt;
  /// Get the result of a SQL SELECT COUNT(...) query.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Seeing if one record exists===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;record_exists($table, array $conditions=null) &lt;br /&gt;
  /// Test whether a record exists in a table where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;record_exists_select($table, $select, array $params=null) &lt;br /&gt;
  /// Test whether any records exists in a table which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;record_exists_sql($sql, array $params=null) &lt;br /&gt;
  /// Test whether a SQL SELECT statement returns any records.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
=====moodle_database::get_records()=====&lt;br /&gt;
Get a number of records as an array of objects where all the given conditions met.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records where foo = bar&lt;br /&gt;
$result = $DB-&amp;gt;get_records($table,array(&#039;foo&#039;=&amp;gt;&#039;bar&#039;));&lt;br /&gt;
&lt;br /&gt;
///Get all records where foo = bar and jon = doe&lt;br /&gt;
$result = $DB-&amp;gt;get_records($table,array(&#039;foo&#039; =&amp;gt; &#039;bar&#039; , &#039;jon&#039; =&amp;gt; &#039;doe&#039;));&lt;br /&gt;
&lt;br /&gt;
///Get all records where foo = bar, but only return the fields foo,bar,jon,doe&lt;br /&gt;
$result = $DB-&amp;gt;get_records($table,array(&#039;foo&#039;=&amp;gt;&#039;bar&#039;),null,&#039;foo,bar,jon,doe&#039;);&lt;br /&gt;
///The previous example would cause data issues unless the &#039;foo&#039; field happens to have unique values.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_select()=====&lt;br /&gt;
Get a number of records as an array of objects which match a particular WHERE clause.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records where jon = &#039;doe&#039; and bob is not = &#039;tom&#039;&lt;br /&gt;
///The &#039;select&#039; parameter is (if not empty) is dropped directly into the WHERE clause without alteration.&lt;br /&gt;
$table = &#039;foo&#039;;&lt;br /&gt;
$select = &amp;quot;jon = &#039;doe&#039; AND bob &amp;lt;&amp;gt; &#039;tom&#039;&amp;quot;; //is put into the where clause&lt;br /&gt;
$result = $DB-&amp;gt;get_records_select($table,$select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_sql()=====&lt;br /&gt;
Get a number of records as an array of objects using a SQL statement. Defined as an abstract function in moodle_database, this method is implemented per database type.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records from &#039;table&#039; where foo = bar&lt;br /&gt;
$result = $DB-&amp;gt;get_records_sql(&#039;SELECT * FROM {table} WHERE foo = ?&#039;, array(&#039;bar&#039;));&lt;br /&gt;
&lt;br /&gt;
///Get all records from &#039;table&#039; where foo = &#039;bar&#039; and bob = &#039;tom&#039;&lt;br /&gt;
///This is somewhat similar to how Drupal makes its queries&lt;br /&gt;
$result = $DB-&amp;gt;get_records_sql(&#039;SELECT * FROM {table} WHERE foo = ? AND bob = ?&#039;, array( &#039;bar&#039; , &#039;tom&#039; ));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_list()=====&lt;br /&gt;
Get a number of records as an array of objects where one field match one list of values.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records where the values(&#039;bar&#039;, &#039;elephant&#039;, &#039;moodle&#039;) are found in the field &#039;foo&#039;&lt;br /&gt;
$result = $DB-&amp;gt;get_records_list($table, &#039;foo&#039;, array( &#039;bar&#039;, &#039;elephant&#039;, &#039;moodle&#039;));&lt;br /&gt;
&lt;br /&gt;
///Get all records where the values(&#039;bar&#039;, &#039;elephant&#039;, &#039;moodle&#039;) are found in the field &#039;foo&#039;&lt;br /&gt;
///Only returning the fields &#039;id&#039;, &#039;test&#039; and &#039;taco&#039;&lt;br /&gt;
$result = $DB-&amp;gt;get_records_list($table, &#039;foo&#039;, array( &#039;bar&#039;, &#039;elephant&#039;, &#039;moodle&#039;), null, &#039;id,test,taco&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_menu()=====&lt;br /&gt;
Get the first two columns from a number of records as an associative array where all the given conditions met. &lt;br /&gt;
You can choose the two fields or leave the parameter blank and the method will return the first two columns of the table.&lt;br /&gt;
Returns an associative array. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records from table &#039;foo&#039; where column &#039;foo&#039; is equal to the value &#039;bar&#039;&lt;br /&gt;
$table = &#039;foo&#039;; ///name of table&lt;br /&gt;
$conditions = array(&#039;foo&#039;=&amp;gt;&#039;bar&#039;); ///the name of the field (key) and the desired value&lt;br /&gt;
&lt;br /&gt;
$result = $DB-&amp;gt;get_records_menu($table,$conditions));&lt;br /&gt;
&lt;br /&gt;
///Get all records from table &#039;foo&#039; where column &#039;foo&#039; is equal to the value &#039;bar&#039;&lt;br /&gt;
///Returning the values from the columns &#039;id&#039; and &#039;tacos&#039;&lt;br /&gt;
$table = &#039;foo&#039;; ///name of table&lt;br /&gt;
$conditions = array(&#039;foo&#039;=&amp;gt;&#039;bar&#039;); ///the name of the field (key) and the desired value&lt;br /&gt;
$sort = &#039;id&#039;; //field or fields you want to sort the result by&lt;br /&gt;
$fields = &#039;id, tacos&#039;; ///list of fields to return&lt;br /&gt;
&lt;br /&gt;
$result = $DB-&amp;gt;get_records_menu($table,$conditions,$sort,$fields));  //If you do not specify $fields, the first two columns of the table will be returned&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The result of this last example will look something like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// The value of the id field  is 909 and the value of the &#039;tacos&#039; column is 6&lt;br /&gt;
array(1) { [909]=6 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_select_menu()=====&lt;br /&gt;
Get the first two columns from a number of records as an associative array which match a particular WHERE clause.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records where jon = &#039;doe&#039; and bob is not = &#039;tom&#039;&lt;br /&gt;
///The &#039;select&#039; parameter is (if not empty) is dropped directly into the WHERE clause without alteration.&lt;br /&gt;
$table = &#039;foo&#039;;&lt;br /&gt;
$select = &#039;jon = &amp;quot;doe&amp;quot; AND bob != &amp;quot;tom&amp;quot; &#039;; //is put into the where clause&lt;br /&gt;
$result = $DB-&amp;gt;get_records_select_menu($table,$select);&lt;br /&gt;
&lt;br /&gt;
$table = &#039;foo&#039;;&lt;br /&gt;
$select = &#039;jon = &amp;quot;doe&amp;quot; AND bob != &amp;quot;tom&amp;quot; &#039;; //is put into the where clause&lt;br /&gt;
$fields = &#039;id, tacos&#039;;//return these fields&lt;br /&gt;
$sort = &#039;id&#039;; //field or fields you want to sort the result by&lt;br /&gt;
$result = $DB-&amp;gt;get_records_select_menu($table,$select,null,$sort,$fields);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result of this last example will look something like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// The value of the id field  is 909 and the value of the &#039;tacos&#039; column is 6&lt;br /&gt;
array(1) { [909]=6 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====moodle_database::get_records_sql_menu()=====&lt;br /&gt;
Get the first two columns from a number of records as an associative array using a SQL statement.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
///Get all records from table foo where bar = 6&lt;br /&gt;
$sql = &#039;SELECT * FROM foo WHERE bar = ?&#039;;&lt;br /&gt;
$params = array(6);&lt;br /&gt;
&lt;br /&gt;
$result = $DB-&amp;gt;get_records_sql_menu($sql,$params);&lt;br /&gt;
&lt;br /&gt;
///Get all records from table foo where bar = 6&lt;br /&gt;
$sql = &#039;SELECT id,tacos FROM foo WHERE bar = ?&#039;;&lt;br /&gt;
$params = array(6);&lt;br /&gt;
&lt;br /&gt;
$result = $DB-&amp;gt;get_records_sql_menu($sql,$params);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result of this last example will look something like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// The value of the id field  is 909 and the value of the &#039;tacos&#039; column is 6&lt;br /&gt;
array(1) { [909]=6 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Getting a particular field value from one record===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_field($table, $return, array $conditions, $strictness=IGNORE_MISSING)&lt;br /&gt;
  /// Get a single field value from a table record where all the given conditions met.&lt;br /&gt;
  /// @param int $strictness&lt;br /&gt;
  ///   IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found;&lt;br /&gt;
  ///   IGNORE_MULTIPLE means return first, ignore multiple records found(not recommended);&lt;br /&gt;
  ///   MUST_EXIST means throw exception if no record or multiple records found&lt;br /&gt;
o $DB-&amp;gt;get_field_select($table, $return, $select, array $params=null, $strictness=IGNORE_MISSING)&lt;br /&gt;
  /// Get a single field value from a table record which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_field_sql($sql, array $params=null, $strictness=IGNORE_MISSING)&lt;br /&gt;
  /// Get a single field value (first field) using a SQL statement.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Getting a particular field value from various records===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_fieldset_select($table, $return, $select, array $params=null)&lt;br /&gt;
  /// Selects records and return values of chosen field as an array which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_fieldset_sql($sql, array $params=null)&lt;br /&gt;
  /// Selects records and return values (first field) as an array using a SQL statement.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setting a particular field in the database===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;set_field($table, $newfield, $newvalue, array $conditions=null)&lt;br /&gt;
  /// Set a single field in every table record where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;set_field_select($table, $newfield, $newvalue, $select, array $params=null)&lt;br /&gt;
  /// Set a single field in every table record which match a particular WHERE clause.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting Records===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;delete_records($table, array $conditions=null) &lt;br /&gt;
  /// Delete the records from a table where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;delete_records_select($table, $select, array $params=null)&lt;br /&gt;
  /// Delete one or more records from a table which match a particular WHERE clause.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Inserting Records===&lt;br /&gt;
The method to insert records is called aptly enough, insert_record(). The method accepts 4 parameters, but the fourth, &amp;quot;bulk&amp;quot;, in most implementations is unused.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;insert_record($table, $dataobject, $returnid=true, $bulk=false) &lt;br /&gt;
  /// Insert a record into a table and return the &amp;quot;id&amp;quot; field if required.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====Example(s)====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$record = new stdClass();&lt;br /&gt;
$record-&amp;gt;name         = &#039;overview&#039;;&lt;br /&gt;
$record-&amp;gt;displayorder = &#039;10000&#039;;&lt;br /&gt;
$DB-&amp;gt;insert_record(&#039;quiz_report&#039;, $record, false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$record = new stdClass();&lt;br /&gt;
$record-&amp;gt;name         = &#039;overview&#039;;&lt;br /&gt;
$record-&amp;gt;displayorder = &#039;10000&#039;;&lt;br /&gt;
$lastinsertid = $DB-&amp;gt;insert_record(&#039;quiz_report&#039;, $record);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating Records===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;update_record($table, $dataobject, $bulk=false)&lt;br /&gt;
  /// Update a record in a table.&lt;br /&gt;
  /// &lt;br /&gt;
  /// $dataobject is an object containing needed data&lt;br /&gt;
  /// Relies on $dataobject having a variable &amp;quot;id&amp;quot; to&lt;br /&gt;
  /// specify the record to update&lt;br /&gt;
  /// &lt;br /&gt;
  /// @param string $table The database table to be checked against.&lt;br /&gt;
  /// @param object $dataobject An object with contents equal to fieldname=&amp;gt;fieldvalue.&lt;br /&gt;
  ///        Must have an entry for &#039;id&#039; to map to the table specified.&lt;br /&gt;
  /// @param bool $bulk true means repeated updates expected&lt;br /&gt;
  /// @return bool true&lt;br /&gt;
  /// @throws dml_exception if an error occurs.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using Recordsets===&lt;br /&gt;
&lt;br /&gt;
Where the number of records to be retrieved from DB is high, the &#039;&#039;&#039;get_records_xxx()&#039;&#039;&#039; functions above are far from optimal, because they load all the records in memory at the same time. Under those circumstances, it is highly recommended to use these &#039;&#039;&#039;get_recordset_xxx()&#039;&#039;&#039; functions instead, which use one nice mechanism to iterate over all the target records and save a lot of memory.&lt;br /&gt;
&lt;br /&gt;
Only one thing is &#039;&#039;&#039;absolutely important&#039;&#039;&#039;: Don&#039;t forget to close the recordsets after using them! (This will free up a lot of resources in the RDBMS).&lt;br /&gt;
&lt;br /&gt;
Here is the general way to iterate over records using the &#039;&#039;&#039;get_recordset_xxx()&#039;&#039;&#039; functions:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$rs = $DB-&amp;gt;get_recordset(....) {&lt;br /&gt;
foreach ($rs as $record) {&lt;br /&gt;
    // Do whatever you want with this record&lt;br /&gt;
}&lt;br /&gt;
$rs-&amp;gt;close(); // Don&#039;t forget to close the recordset!&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this is the list of available functions (100% paired with the get_records_xxx() above):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;get_recordset($table, array $conditions=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0) &lt;br /&gt;
  /// Get a number of records as a moodle_recordset where all the given conditions met.&lt;br /&gt;
o $DB-&amp;gt;get_recordset_select($table, $select, array $params=null, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=0, $limitnum=0) &lt;br /&gt;
  /// Get a number of records as a moodle_recordset which match a particular WHERE clause.&lt;br /&gt;
o $DB-&amp;gt;get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0);&lt;br /&gt;
  /// Get a number of records as a moodle_recordset using a SQL statement.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;get_recordset_list($table, $field=&#039;&#039;, $values=&#039;&#039;, $sort=&#039;&#039;, $fields=&#039;*&#039;, $limitfrom=&#039;&#039;, $limitnum=&#039;&#039;) &lt;br /&gt;
  /// Get a number of records as a moodle_recordset where one field matches one list of values.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unlike get_record functions, you cannot use &amp;lt;tt&amp;gt;$rs == true&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;!empty($rs)&amp;lt;/tt&amp;gt; to determine if any records were found.&lt;br /&gt;
Recordsets implement the standard PHP Iterator interface (http://uk.php.net/manual/en/class.iterator.php)&lt;br /&gt;
&lt;br /&gt;
So,&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($rs-&amp;gt;valid()) {&lt;br /&gt;
    // The recordset contains records.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Delegated transactions===&lt;br /&gt;
&lt;br /&gt;
* Please note some databases do not support transactions (such as the MyISAM MySQL database engine), however all server administrators are strongly encouraged to migrate to databases that support transactions (such as the InnoDB MySQL database engine).&lt;br /&gt;
* Previous versions supported only one level of transaction. Since Moodle 2.0, the DML layer emulates delegated transactions that allow nesting of transactions.&lt;br /&gt;
* Transactions should not be used much in Moodle core; they are intended for various plugins such as web services, enrol and auth plugins.&lt;br /&gt;
* Some subsystems (such as messaging) do not support transactions because is it is not possible to rollback in external systems.&lt;br /&gt;
&lt;br /&gt;
A transaction is started by:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$transaction = $DB-&amp;gt;start_delegated_transaction();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and finished by:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$transaction-&amp;gt;allow_commit();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually a transaction is rolled back when an exception is thrown. &amp;lt;code&amp;gt;$transaction-&amp;gt;rollback($ex);&amp;lt;/code&amp;gt; must be used very carefully because it might break compatibility with databases that do not support transactions. Transactions cannot be used as part of expected code flow; they can be used only as an emergency protection of data consistency.&lt;br /&gt;
&lt;br /&gt;
See more details in [[DB layer 2.0 delegated transactions]] or MDL-20625.&lt;br /&gt;
&lt;br /&gt;
====Example(s)====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
try {&lt;br /&gt;
     $transaction = $DB-&amp;gt;start_delegated_transaction();&lt;br /&gt;
     // Insert a record&lt;br /&gt;
     $DB-&amp;gt;insert(&#039;foo&#039;, $object);&lt;br /&gt;
     $DB-&amp;gt;insert(&#039;bar&#039;, $otherobject);&lt;br /&gt;
&lt;br /&gt;
     // Assuming the both inserts work, we get to the following line.&lt;br /&gt;
     $transaction-&amp;gt;allow_commit();&lt;br /&gt;
} catch(Exception $e) {&lt;br /&gt;
     $transaction-&amp;gt;rollback($e);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
In order have real cross-db compatibility, there are some helper functions used to build SQL fragments based on the DB Moodle is running. Using them we&#039;ll avoid conditional queries here and there and have those &amp;quot;incompatibilities&amp;quot; fixed once and for ever.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
o $DB-&amp;gt;sql_bitand($int1, $int2) &lt;br /&gt;
  /// Returns the SQL text to be used in order to perform one bitwise AND &lt;br /&gt;
  /// operation between 2 integers.&lt;br /&gt;
o $DB-&amp;gt;sql_bitnot($int1) &lt;br /&gt;
  /// Returns the SQL text to be used in order to perform one bitwise NOT &lt;br /&gt;
  /// operation with 1 integer.&lt;br /&gt;
o $DB-&amp;gt;sql_bitor($int1, $int2)&lt;br /&gt;
  /// Returns the SQL text to be used in order to perform one bitwise OR &lt;br /&gt;
  /// operation between 2 integers.&lt;br /&gt;
o $DB-&amp;gt;sql_bitxor($int1, $int2) &lt;br /&gt;
  /// Returns the SQL text to be used in order to perform one bitwise XOR &lt;br /&gt;
  /// operation between 2 integers.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_null_from_clause()&lt;br /&gt;
  /// Returns the FROM clause required by some DBs in all SELECT statements.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_ceil($fieldname)&lt;br /&gt;
  /// Returns the correct CEIL expression applied to fieldname.&lt;br /&gt;
o $DB-&amp;gt;sql_like($fieldname, $param, $casesensitive = true, $accentsensitive = true, $notlike = false, $escapechar = &#039; \\ &#039;)&lt;br /&gt;
  /// Returns the proper SQL to do LIKE. For example:&lt;br /&gt;
  $DB-&amp;gt;get_records_sql(&#039;SELECT ...  WHERE &#039;.$DB-&amp;gt;sql_like(&#039;idnumber&#039;, &#039;:idnum&#039;).&#039; ... &#039;, array( &#039;idnum&#039; =&amp;gt; &#039;foo&#039;));&lt;br /&gt;
&lt;br /&gt;
o $DB-&amp;gt;sql_length($fieldname)&lt;br /&gt;
  /// Returns the SQL text to be used to calculate the length in characters of one expression.&lt;br /&gt;
o $DB-&amp;gt;sql_modulo($int1, $int2)&lt;br /&gt;
  /// Returns the SQL text to be used in order to calculate module - remainder after division&lt;br /&gt;
o $DB-&amp;gt;sql_position($needle, $haystack)&lt;br /&gt;
  /// Returns the SQL for returning searching one string for the location of another.&lt;br /&gt;
  /// Note: If using placeholders BOTH in $needle and $haystack, they MUST be named placeholders.&lt;br /&gt;
o $DB-&amp;gt;sql_substr($expr, $start, $length=false)&lt;br /&gt;
  /// Returns the proper substr() SQL text used to extract substrings from DB.&lt;br /&gt;
  /// Note: This fuction has changed in Moodle 2.0 and now at least 2 params are mandatory.&lt;br /&gt;
  /// Note: Now it returns the whole SQL text to be used instead of only the function name.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_cast_char2int($fieldname, $text=false)&lt;br /&gt;
  /// Returns the SQL to be used in order to CAST one CHAR column to INTEGER.&lt;br /&gt;
o $DB-&amp;gt;sql_cast_char2real($fieldname, $text=false)&lt;br /&gt;
  /// Returns the SQL to be used in order to CAST one CHAR column to REAL number.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_compare_text($fieldname, $numchars=32) &lt;br /&gt;
  /// Returns the SQL text to be used to compare one TEXT (clob) column.&lt;br /&gt;
  /// with one VARCHAR column.&lt;br /&gt;
o $DB-&amp;gt;sql_order_by_text($fieldname, $numchars=32)&lt;br /&gt;
  /// Returns the SQL text to be used to order by one TEXT (clob) column.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_concat()&lt;br /&gt;
  /// Returns the proper SQL to do CONCAT between the elements passed.&lt;br /&gt;
o $DB-&amp;gt;sql_concat_join($separator=&amp;quot;&#039; &#039;&amp;quot;, $elements=array())&lt;br /&gt;
  /// Returns the proper SQL to do CONCAT between the elements passed using one separator.&lt;br /&gt;
o $DB-&amp;gt;sql_fullname($first=&#039;firstname&#039;, $last=&#039;lastname&#039;)&lt;br /&gt;
  /// Returns the proper SQL to concatenate $firstname and $lastname.&lt;br /&gt;
 &lt;br /&gt;
o $DB-&amp;gt;sql_isempty($tablename, $fieldname, $nullablefield, $textfield)&lt;br /&gt;
  /// Returns the proper SQL to know if one field is empty.&lt;br /&gt;
o $DB-&amp;gt;sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield)&lt;br /&gt;
  /// Returns the proper SQL to know if one field is not empty.&lt;br /&gt;
o $DB-&amp;gt;sql_empty()&lt;br /&gt;
  /// Returns the empty string char used by every supported DB.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[DML exceptions|DML exceptions]]: New DML code is throwing exceptions instead of returning false if anything goes wrong&lt;br /&gt;
* [[DML drivers|DML drivers]]: Database drivers for new DML layer&lt;br /&gt;
* [[DML functions - pre 2.0|DML functions - pre 2.0]]: &#039;&#039;&#039;(deprecated!)&#039;&#039;&#039; For information valid before Moodle 2.0.&lt;br /&gt;
* [[DDL functions|DDL functions]]: Where all the functions used to handle DB objects ([[wikipedia:Data_Definition_Language|DDL]]) are defined.&lt;br /&gt;
* [[DB layer 2.0 examples|DB layer 2.0 examples]]: To see some code examples using various DML functions.&lt;br /&gt;
* [[DB layer 2.0 migration docs|DB layer 2.0 migration docs]]: Information about how to modify your code to work with the new Moodle 2.0 DB layer.&lt;br /&gt;
* [[DTL functions|DTL functions]]: Exporting, importing and moving of data stored in SQL databases&lt;br /&gt;
&lt;br /&gt;
[[Category:DB]]&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Data_manipulation_API&amp;diff=34607</id>
		<title>Data manipulation API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Data_manipulation_API&amp;diff=34607"/>
		<updated>2012-08-01T03:27:30Z</updated>

		<summary type="html">&lt;p&gt;Aolley: Bare bones entry&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.2}}This page describes the API used by the Engagement Analytics indicators and reporting mechanisms.&lt;br /&gt;
&lt;br /&gt;
== Main info ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039; This page is a WIP and does not reflect the final state of the engagement analytics API!&lt;br /&gt;
&lt;br /&gt;
== The indicator class ==&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====indicator_random====&lt;br /&gt;
Return a random risk score for each user.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
require_once(dirname(__FILE__).&#039;/../indicator.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class indicator_random extends indicator {&lt;br /&gt;
    protected function get_risk_for_users($userids, $courseid, $startdate, $enddate) {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_defaults() {&lt;br /&gt;
        // TODO: Fill this in.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // TODO: Complete class definition.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Helper Functions===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;/div&gt;</summary>
		<author><name>Aolley</name></author>
	</entry>
</feed>