NEWMODULE Adding capabilities
In order to add a capabilities for your <<NEWMODULE>> you need to:
1. Create a file access.php in the <<NEWMODULE>>/db directory
This should contain a list of the capabilities that you want to define. For example:
$capabilities = array(
'mod/<<NEWMODULE>>:<<CAPABILITYNAME>>' => array(
'riskbitmask' => RISK_SPAM | RISK_PERSONAL | RISK_XSS | RISK_CONFIG,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
// Add more capabilities here ...
)
The various parts of the capability definition are:
Capability name ('mod/<<NEWMODULE>>:<<CAPABILITYNAME>>)
This is the internal name used for this this capability. In addition to this internal name, you should also add the language string <<NEWMODULE>>:<<CAPABILITYNAME>> to your module's language file, to give the capability a name that users will see in the interface.
riskbitmask
Allowing people to do various things sometimes requires introducing possible security risks. For example, if you can post to a forum, you can post unsolicited advertising. To a certain extent users have to be trusted. To help administrators and teachers know what the issues are, each capability should list any associated risks. See Hardening_new_Roles_system. will be reflected in the list of icons of each row of the 'Override permissions'->roles page.
Technically, this value is a bit field, so you should combine the relevant risks constants with the '|' operator. So typical values might be:
- RISK_SPAM
- RISK_PERSONAL | RISK_XSS | RISK_DATALOSS
captype
Should be either 'read' or 'write'. 'read' is for capabilities that just let you view things. 'write' for capabilities that let you change things.
contextlevel
The context level where this capability is most relevant. If you are writing a module this will almost always be CONTEXT_MODULE. (This does not have much effect. It is just used to sort and group capabilities on the define roles and override roles pages.)
archetypes
This section defines, for each role type, what default permissions those roles should be given when your module is first installed (or when a new capability is detected on upgrade).
Normally, you just add one line for each role that you want to give the capability to. The line should look like 'roletype' => CAP_ALLOW. Just leave out roles that you do not want to get the capability by default. Very exceptionally, you may need to specify a default permission of CAP_PREVENT, CAP_PROHIBIT.
Note that once a capability is established, permissions will not be automatically overwritten when a module is updated. If permissions have changed, an administrator must manually change or force capabilities to be reset to default for a role.
If you don't want to specify any roles that will be given your capability by default, you can pass a blank array to the 'archetypes' parameter:
'mod/newmodule:dosomething' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array()
),
2. Get Moodle to load the updated capabilities
The capabilities you defined are only read (and copied into the Moodle database) when your module is installed or upgraded. So every time you edit the db/access.php file you must
- Increase your module's version number by editing the file mod/<<NEWMODULE>>/version.php.
- Go to the the Administration ► Notifications page, and click through the steps to let Moodle upgrade itself. You should see the name of your module in one of the steps.
3. Checking the capability in your code
In order to check whether the current user has a particular capability, you need to use the has_capability function. To do that, first you have to get the appropriate context. In this case, it will be a module context.
1. First we need to get the $cm id, and verify that it is correct (there are lots of different ways you might do this, this is only an example.
$cmid = required_param('cmid', PARAM_INT);
if (!$cm = get_coursemodule_from_id('<<NEWMODULE>>', $cmid)) {
error("Course module ID was incorrect");
}
2. Then you get the module context:
$context = context_module::instance($cm->id);
//for course use below code
//$context = context_course::instance($cm->id);
//for system
//$context = context_system::instance($cm->id);
3. Finally, you can actually check the permission
if (has_capability('mod/<<NEWMODULE>>:<<CAPABILITYNAME>>', $context)) {
Normally, you do 1. and 2. once at the top of a script, and then call has_capability as needed within the script with the appropriate capabilities.
Useful variations
Controlling overall access to a script
Suppose you have a page that should only be available to users with a particular capability. For example, only users with mod/quiz:viewreports should be able to access mod/quiz/report.php. In cases like this, you can use the require_capability function:
require_capability($capability, $context);
near the top of your script. (As soon as you have got the context and called require_login is a good time.) All this does internally is
if (!has_capability($capability, $context)) {
// Display error and exit.
}
but using require_capability makes your code simpler and is recommended. (Of course, anywhere you might print a link to a page like this, you should only print the link if the user has the right capability.)
Getting a list of users with a capability
Suppose you need to get a list of all the users with a particular capability. (For example, the quiz reports list all the users with the mod/quiz:attempt capability. Then you can use the get_users_by_capability function.
Checking the permissions of another user
There is an optional 3rd parameter to has_capability that you can use to check another user's permissions:
has_capability($capability, $context, $otheruser->id);
Excluding administrators
Administrators have a magic 'moodle/site:doanything' capability that gives them every other capability. If you wish to disable that magic override for one particular capability check, you can use the optional 4th parameter to has capability:
has_capability($capability, $context, NULL, false);
However, you normally should not do this.
Performance considerations
The has_capability function has been carefully optimised, and is pretty fast and you should not really worry. However, it has to perform a fairly complex computation, and if you are going to make exactly the same has_capability call several times in a page (perhaps in a loop) it is probably worth moving the permission check outside the loop. For example don't do:
foreach ($attempts as $attempt) {
if (has_capability('mod/quiz:viewreports', $context)) {
// ...
}
}
Instead do
$canviewreports = has_capability('mod/quiz:viewreports', $context);
foreach ($attempts as $attempt) {
if ($canviewreports) {
// ...
}
}
get_users_by_capability is a very expensive computation. If you are calling it more than once in your script, you are probably doing something wrong ;-)
See also
- Access API
- Roles
- Hardening_new_Roles_system - information about risks
- NEWMODULE_Documentation - NEWMODULE Documentation front page