In this blog entry, I’d like to go through some basic concepts of the Moodle architecture. We will look at very common but sometimes confusing parts of Moodle: instance IDs, contexts and coursemodules.
To explain the concepts we will use an actual Moodle 2.3 installation. We will look at what is happening in Moodle UI and also “behind the scenes” – in the Moodle database.
In Moodle everything starts with a course, so I’ve started by adding a new course which I’ve called “Moodle development course”.
By creating this course a number of database entries are made. In the following I outline what has been created in mdl_course and mdl_course_sections tables (I’m showing only few columns and few rows):
mdl_course id: 6 category: 1 sortorder: 10001 fullname: Moodle development course shortname: moodle dev 101 #more columns.... mdl_course_sections - id: 36 course: 6 section: 0 summaryformat: 1 sequence: 7 visible: 1 - id: 37 course: 6 section: 1 summary: summaryformat: 1 visible: 1 #more rows....
Our course id is 6 and several sections have been created – one row in mdl_course_sections for each section. Using Moodle UI, I’m now adding the new “Assignment” activity (new to M2.3). I called it “New assignment activity” and it’s been added to the first section (week 0) of my course.
When I click the link to this assignment, it will open following URL:
The number at the end – “9″ is “Course Module ID”. It is stored in mdl_course_modules table as mdl_course_modules.id. If we look there for a row with id=9, we will find our new assignment:
mdl_course_modules id: 9 course: 6 module: 21 instance: 1 section: 36 #more columns...
We can see that course=6 matches mdl_course.id and section=36 matches mdl_course_sections.id – that must be our new assignment.
Once we have course module id, we usually want to get “Course Module Object” that contains full information about “coursemodule”. This can be done with Moodle API function get_coursemodule_from_id($modulename, $cmid);
In our example we would use the following code:
$cm = get_coursemodule_from_id('assign', 9);
Keep in mind that “assign” is a module name and the name comes from “assignment”.
Of course you would never hard-code ID number like that but use required_param() instead – but we won’t cover it here.
To see the actual value of $cm I used following snippet:
$cm = get_coursemodule_from_id('assign', 9); print_r($cm);
and the result is:
stdClass Object ( [id] => 9 [course] => 6 [module] => 21 [instance] => 1 [section] => 36 [idnumber] => [added] => 1336640971 [score] => 0 [indent] => 0 [visible] => 1 [visibleold] => 1 [groupmode] => 0 [groupingid] => 0 [groupmembersonly] => 0 [completion] => 0 [completiongradeitemnumber] => [completionview] => 0 [completionexpected] => 0 [availablefrom] => 0 [availableuntil] => 0 [showavailability] => 1 [showdescription] => 0 [name] => New assignment activity [modname] => assign )
There is a very similar API function get_coursemodule_from_instance($modulename, $instance) that can be used to retrieve $cm as well. This may be a bit confusing as the API function name ends with _instance but the second argument is really an id as well. Just in this case, the second parameter is an id of a module in its own table. The table that stores information about instances of “assign” module is called mdl_assign. If I look inside that table, there is just one row – for the activity I’ve just created:
mdl_assign id: 1 course: 6 name: New assignment activity intro: New assignment activity #more columns...
This means that those two invocations should result in exactly the same $cm object:
$cm = get_coursemodule_from_id('assign', 9); $cm = get_coursemodule_from_instance('assign', 1);
Any time you see $cm in Moodle code you can be fairly sure it is a coursemodule object.
We will now move on to another concept – “context”. Contexts are mainly used for permission checking. In case of our “assign” activity, there must be a check if a user can submit new assignment or another check to see if user is allowed to grade the submissions (teacher).
Each activity will have it’s own context but other Moodle elements will have context as well: courses, users or categories. All context levels are defined in lib/accesslib.php:
define('CONTEXT_SYSTEM', 10); define('CONTEXT_USER', 30); define('CONTEXT_COURSECAT', 40); define('CONTEXT_COURSE', 50); define('CONTEXT_MODULE', 70); define('CONTEXT_BLOCK', 80);
To retrieve context for our “assign” activity, we will be looking at CONTEXT_MODULE level. Current context you are working on is usually put into variable named $context. The API call to retrieve context is:
$context = context_module::instance($cm->id); //$cm->id = 9 for us
Let’s see what is inside $context
context_module Object ( [_id:protected] => 51 [_contextlevel:protected] => 70 [_instanceid:protected] => 9 [_path:protected] => /1/3/44/51 [_depth:protected] => 4 )
- id comes from mdl_context.id – a table that stores all contexts in Moodle. All the information in this object is basically a row from mdl_context
- contextlevel equals CONTEXT_MODULE (70)
- instanceid equals to $cm->id
- path is a full path from top, to this context
- depth is a depth of the path above. In other words it should equal to the number of slashes in the path
The numbers in the path (/1/3/44/51) are context IDs. The very first ID will always be “1″. This is the only CONTEXT_SYSTEM level context. Next we see “3″, let’s see what it is in mdl_context:
mdl_context id: 3 contextlevel: 40 instanceid: 1 path: /1/3 depth: 2
After looking at contextlevel, we can infer that this is CONTEXT_COURSECAT – a course category (contextlevel equals 40, which is the same as integer defined for constant CONTEXT_COURSECAT). It has instanceid=1, so we can find it in mdl_course_categories where id = 1. Turns out, this is a default, Miscellaneous category.
Next context ID is 44:
mdl_context id: 44 contextlevel: 50 instanceid: 6 path: /1/3/44 depth: 3
That’s our course where we’ve added the activity (CONTEXT_COURSE=50). You can see that instanceid = 6 matches our mdl_course.id.
With the $context object we can now use Moodle APIs like has_capability() or require_capability(). They will go through context path and check access on each level. This means, for example, checking if the access to an activity is blocked from the system context, then on the category level, then in our course and finally in this instance of “assign” activity.
To summarize: every activity you add to a course will have an entry in it’s own table (e.g. mdl_assign). Id in this table is usually referred to as instance or instanceid (mdl_assign.id). Every activity will also have a row in mdl_course_modules table. Based on this row, $cm object is created. Finally, every activity will have a context with level equal CONTEXT_COURSE (50). This will usually be stored in $context variable and used for permission checks.