2009-05-19 07:50:54 +00:00
< ? php
2009-11-01 11:31:16 +00:00
// This file is part of Moodle - http://moodle.org/
//
2009-05-19 07:50:54 +00:00
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
2009-11-01 11:31:16 +00:00
//
2009-05-19 07:50:54 +00:00
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
2007-08-06 17:55:44 +00:00
2007-09-19 07:15:27 +00:00
/**
2009-05-19 07:50:54 +00:00
* This file contains functions for managing user access
*
2009-05-22 02:03:55 +00:00
* < b > Public API vs internals </ b >
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:15:27 +00:00
* General users probably only care about
*
2007-09-19 07:57:10 +00:00
* Context handling
2011-10-14 12:48:00 +02:00
* - context_course :: instance ( $courseid ), context_module :: instance ( $cm -> id ), context_coursecat :: instance ( $catid )
* - context :: instance_by_id ( $contextid )
* - $context -> get_parent_contexts ();
* - $context -> get_child_contexts ();
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:57:10 +00:00
* Whether the user can do something ...
2007-09-19 07:15:27 +00:00
* - has_capability ()
2008-12-08 07:28:19 +00:00
* - has_any_capability ()
* - has_all_capabilities ()
2007-09-19 07:24:43 +00:00
* - require_capability ()
2007-09-19 07:57:10 +00:00
* - require_login () ( from moodlelib )
2012-01-14 19:12:43 +01:00
* - is_enrolled ()
* - is_viewing ()
* - is_guest ()
2011-10-14 12:48:00 +02:00
* - is_siteadmin ()
2012-01-14 19:12:43 +01:00
* - isguestuser ()
* - isloggedin ()
2007-09-19 07:57:10 +00:00
*
* What courses has this user access to ?
2011-10-14 12:48:00 +02:00
* - get_enrolled_users ()
2007-09-19 07:57:10 +00:00
*
2008-04-29 06:53:19 +00:00
* What users can do X in this context ?
2012-01-14 19:12:43 +01:00
* - get_enrolled_users () - at and bellow course context
* - get_users_by_capability () - above course context
2008-04-29 06:53:19 +00:00
*
2011-10-14 12:48:00 +02:00
* Modify roles
* - role_assign ()
* - role_unassign ()
* - role_unassign_all ()
2008-05-24 18:35:48 +00:00
*
2011-10-14 12:48:00 +02:00
* Advanced - for internal use only
2007-09-19 07:57:10 +00:00
* - load_all_capabilities ()
* - reload_all_capabilities ()
2007-09-20 04:52:54 +00:00
* - has_capability_in_accessdata ()
2016-05-14 21:14:31 +09:30
* - get_user_roles_sitewide_accessdata ()
2011-10-14 12:48:00 +02:00
* - etc .
2007-09-19 07:57:10 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > Name conventions </ b >
2008-05-24 18:35:48 +00:00
*
2009-05-22 02:03:55 +00:00
* " ctx " means context
2018-06-05 15:13:02 -04:00
* " ra " means role assignment
* " rdef " means role definition
2007-09-19 07:15:27 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > accessdata </ b >
2007-09-19 07:15:27 +00:00
*
* Access control data is held in the " accessdata " array
* which - for the logged - in user , will be in $USER -> access
2008-05-24 18:35:48 +00:00
*
2009-03-23 03:54:50 +00:00
* For other users can be generated and passed around ( but may also be cached
2011-10-14 12:48:00 +02:00
* against userid in $ACCESSLIB_PRIVATE -> accessdatabyuser ) .
2007-09-19 07:15:27 +00:00
*
2007-09-20 04:52:54 +00:00
* $accessdata is a multidimensional array , holding
2018-06-05 15:13:02 -04:00
* role assignments ( RAs ), role switches and initialization time .
2007-09-19 07:15:27 +00:00
*
2008-05-24 18:35:48 +00:00
* Things are keyed on " contextpaths " ( the path field of
2007-09-19 07:15:27 +00:00
* the context table ) for fast walking up / down the tree .
2009-05-22 02:03:55 +00:00
* < code >
2011-10-14 12:48:00 +02:00
* $accessdata [ 'ra' ][ $contextpath ] = array ( $roleid => $roleid )
* [ $contextpath ] = array ( $roleid => $roleid )
* [ $contextpath ] = array ( $roleid => $roleid )
2009-11-01 11:31:16 +00:00
* </ code >
2007-09-19 07:15:27 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > Stale accessdata </ b >
2007-09-19 07:15:27 +00:00
*
* For the logged - in user , accessdata is long - lived .
*
2009-03-23 03:54:50 +00:00
* On each pageload we load $ACCESSLIB_PRIVATE -> dirtycontexts which lists
2007-09-19 07:15:27 +00:00
* context paths affected by changes . Any check at - or - below
* a dirty context will trigger a transparent reload of accessdata .
2008-05-24 18:35:48 +00:00
*
2010-05-22 18:46:43 +00:00
* Changes at the system level will force the reload for everyone .
2007-09-19 07:15:27 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > Default role caps </ b >
2008-05-24 18:35:48 +00:00
* The default role assignment is not in the DB , so we
* add it manually to accessdata .
2007-09-19 07:15:27 +00:00
*
* This means that functions that work directly off the
* DB need to ensure that the default role caps
2008-05-24 18:35:48 +00:00
* are dealt with appropriately .
2007-09-19 07:15:27 +00:00
*
2012-01-14 19:12:43 +01:00
* @ package core_access
2010-07-25 13:35:05 +00:00
* @ copyright 1999 onwards Martin Dougiamas http :// dougiamas . com
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2007-09-19 07:15:27 +00:00
*/
2006-08-08 05:13:06 +00:00
2010-07-25 13:35:05 +00:00
defined ( 'MOODLE_INTERNAL' ) || die ();
2011-10-14 12:48:00 +02:00
/** No capability change */
2006-09-15 06:07:29 +00:00
define ( 'CAP_INHERIT' , 0 );
2011-10-14 12:48:00 +02:00
/** Allow permission, overrides CAP_PREVENT defined in parent contexts */
2006-08-08 05:13:06 +00:00
define ( 'CAP_ALLOW' , 1 );
2011-10-14 12:48:00 +02:00
/** Prevent permission, overrides CAP_ALLOW defined in parent contexts */
2006-08-08 05:13:06 +00:00
define ( 'CAP_PREVENT' , - 1 );
2011-10-14 12:48:00 +02:00
/** Prohibit permission, overrides everything in current and child contexts */
2006-08-08 05:13:06 +00:00
define ( 'CAP_PROHIBIT' , - 1000 );
2011-10-14 12:48:00 +02:00
/** System context level - only one instance in every system */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_SYSTEM' , 10 );
2011-10-14 12:48:00 +02:00
/** User context level - one instance for each user describing what others can do to user */
2006-09-15 14:09:16 +00:00
define ( 'CONTEXT_USER' , 30 );
2011-10-14 12:48:00 +02:00
/** Course category context level - one instance for each category */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_COURSECAT' , 40 );
2011-10-14 12:48:00 +02:00
/** Course context level - one instances for each course */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_COURSE' , 50 );
2011-10-14 12:48:00 +02:00
/** Course module context level - one instance for each course module */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_MODULE' , 70 );
2011-10-14 12:48:00 +02:00
/**
* Block context level - one instance for each block , sticky blocks are tricky
* because ppl think they should be able to override them at lower contexts .
* Any other context level instance can be parent of block context .
*/
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_BLOCK' , 80 );
2011-10-14 12:48:00 +02:00
/** Capability allow management of trusts - NOT IMPLEMENTED YET - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_MANAGETRUST' , 0x0001 );
2011-10-14 12:48:00 +02:00
/** Capability allows changes in system configuration - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2006-09-19 07:33:22 +00:00
define ( 'RISK_CONFIG' , 0x0002 );
2012-01-14 19:12:43 +01:00
/** Capability allows user to add scripted content - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_XSS' , 0x0004 );
2011-10-14 12:48:00 +02:00
/** Capability allows access to personal user information - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_PERSONAL' , 0x0008 );
2012-01-14 19:12:43 +01:00
/** Capability allows users to add content others may see - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_SPAM' , 0x0010 );
2011-10-14 12:48:00 +02:00
/** capability allows mass delete of data belonging to other users - see {@link http://docs.moodle.org/dev/Hardening_new_Roles_system} */
2008-07-23 16:10:06 +00:00
define ( 'RISK_DATALOSS' , 0x0020 );
2006-09-18 21:32:49 +00:00
2012-05-18 11:40:35 +02:00
/** rolename displays - the name as defined in the role definition, localised if name empty */
2009-05-22 02:03:55 +00:00
define ( 'ROLENAME_ORIGINAL' , 0 );
2012-05-18 11:40:35 +02:00
/** rolename displays - the name as defined by a role alias at the course level, falls back to ROLENAME_ORIGINAL if alias not present */
2009-05-22 02:03:55 +00:00
define ( 'ROLENAME_ALIAS' , 1 );
2011-10-14 12:48:00 +02:00
/** rolename displays - Both, like this: Role alias (Original) */
2009-05-22 02:03:55 +00:00
define ( 'ROLENAME_BOTH' , 2 );
2011-10-14 12:48:00 +02:00
/** rolename displays - the name as defined in the role definition and the shortname in brackets */
2009-05-22 02:03:55 +00:00
define ( 'ROLENAME_ORIGINALANDSHORT' , 3 );
2011-10-14 12:48:00 +02:00
/** rolename displays - the name as defined by a role alias, in raw form suitable for editing */
2009-05-22 02:03:55 +00:00
define ( 'ROLENAME_ALIAS_RAW' , 4 );
2011-10-14 12:48:00 +02:00
/** rolename displays - the name is simply short role name */
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
define ( 'ROLENAME_SHORT' , 5 );
2009-05-22 02:03:55 +00:00
2011-10-14 12:48:00 +02:00
if ( ! defined ( 'CONTEXT_CACHE_MAX_SIZE' )) {
2012-01-14 19:12:43 +01:00
/** maximum size of context cache - it is possible to tweak this config.php or in any script before inclusion of context.php */
2011-10-14 12:48:00 +02:00
define ( 'CONTEXT_CACHE_MAX_SIZE' , 2500 );
2009-04-06 09:48:39 +00:00
}
2009-05-22 02:03:55 +00:00
/**
2009-11-01 11:31:16 +00:00
* Although this looks like a global variable , it isn ' t really .
2009-05-22 02:03:55 +00:00
*
2009-11-01 11:31:16 +00:00
* It is just a private implementation detail to accesslib that MUST NOT be used elsewhere .
* It is used to cache various bits of data between function calls for performance reasons .
2010-05-22 18:46:43 +00:00
* Sadly , a PHP global variable is the only way to implement this , without rewriting everything
2009-05-22 02:03:55 +00:00
* as methods of a class , instead of functions .
*
2012-01-14 19:12:43 +01:00
* @ access private
2009-05-22 02:03:55 +00:00
* @ global stdClass $ACCESSLIB_PRIVATE
* @ name $ACCESSLIB_PRIVATE
*/
2010-08-26 16:10:19 +00:00
global $ACCESSLIB_PRIVATE ;
2010-10-01 21:45:14 +00:00
$ACCESSLIB_PRIVATE = new stdClass ();
2017-03-27 11:44:43 +01:00
$ACCESSLIB_PRIVATE -> cacheroledefs = array (); // Holds site-wide role definitions.
2011-10-14 12:48:00 +02:00
$ACCESSLIB_PRIVATE -> dirtycontexts = null ; // Dirty contexts cache, loaded from DB once per page
2018-06-05 16:37:25 -04:00
$ACCESSLIB_PRIVATE -> dirtyusers = null ; // Dirty users cache, loaded from DB once per $USER->id
2011-10-14 12:48:00 +02:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array (); // Holds the cache of $accessdata structure for users (including $USER)
2006-08-08 05:13:06 +00:00
2009-03-23 03:54:50 +00:00
/**
2009-05-19 07:50:54 +00:00
* Clears accesslib ' s private caches . ONLY BE USED BY UNIT TESTS
2009-11-01 11:31:16 +00:00
*
2009-03-23 03:54:50 +00:00
* This method should ONLY BE USED BY UNIT TESTS . It clears all of
* accesslib ' s private caches . You need to do this before setting up test data ,
2010-05-22 18:46:43 +00:00
* and also at the end of the tests .
2011-10-14 12:48:00 +02:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ return void
2009-03-23 03:54:50 +00:00
*/
function accesslib_clear_all_caches_for_unit_testing () {
2012-07-21 10:11:50 +02:00
global $USER ;
if ( ! PHPUNIT_TEST ) {
2009-03-23 03:54:50 +00:00
throw new coding_exception ( 'You must not call clear_all_caches outside of unit tests.' );
}
2011-10-14 12:48:00 +02:00
accesslib_clear_all_caches ( true );
2018-06-05 15:13:02 -04:00
accesslib_reset_role_cache ();
2009-03-23 03:54:50 +00:00
unset ( $USER -> access );
}
2009-05-19 07:50:54 +00:00
/**
2011-10-14 12:48:00 +02:00
* Clears accesslib ' s private caches . ONLY BE USED FROM THIS LIBRARY FILE !
2009-05-19 07:50:54 +00:00
*
2011-10-14 12:48:00 +02:00
* This reset does not touch global $USER .
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ param bool $resetcontexts
* @ return void
2009-05-19 07:50:54 +00:00
*/
2011-10-14 12:48:00 +02:00
function accesslib_clear_all_caches ( $resetcontexts ) {
global $ACCESSLIB_PRIVATE ;
2006-09-12 06:15:33 +00:00
2011-10-14 12:48:00 +02:00
$ACCESSLIB_PRIVATE -> dirtycontexts = null ;
2018-06-05 16:37:25 -04:00
$ACCESSLIB_PRIVATE -> dirtyusers = null ;
2011-10-14 12:48:00 +02:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array ();
2006-09-12 06:15:33 +00:00
2011-10-14 12:48:00 +02:00
if ( $resetcontexts ) {
context_helper :: reset_caches ();
2006-09-12 06:15:33 +00:00
}
2007-03-07 13:45:41 +00:00
}
2018-06-05 15:13:02 -04:00
/**
* Full reset of accesslib ' s private role cache . ONLY TO BE USED FROM THIS LIBRARY FILE !
*
* This reset does not touch global $USER .
*
* Note : Only use this when the roles that need a refresh are unknown .
*
* @ see accesslib_clear_role_cache ()
*
* @ access private
* @ return void
*/
function accesslib_reset_role_cache () {
global $ACCESSLIB_PRIVATE ;
$ACCESSLIB_PRIVATE -> cacheroledefs = array ();
$cache = cache :: make ( 'core' , 'roledefs' );
$cache -> purge ();
}
2017-03-27 11:44:43 +01:00
/**
* Clears accesslib ' s private cache of a specific role or roles . ONLY BE USED FROM THIS LIBRARY FILE !
*
* This reset does not touch global $USER .
*
* @ access private
* @ param int | array $roles
* @ return void
*/
function accesslib_clear_role_cache ( $roles ) {
global $ACCESSLIB_PRIVATE ;
if ( ! is_array ( $roles )) {
$roles = [ $roles ];
}
foreach ( $roles as $role ) {
if ( isset ( $ACCESSLIB_PRIVATE -> cacheroledefs [ $role ])) {
unset ( $ACCESSLIB_PRIVATE -> cacheroledefs [ $role ]);
}
}
$cache = cache :: make ( 'core' , 'roledefs' );
$cache -> delete_many ( $roles );
}
2007-03-07 13:45:41 +00:00
/**
2016-05-14 21:14:31 +09:30
* Role is assigned at system context .
2007-09-19 07:16:29 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2009-05-19 07:50:54 +00:00
* @ param int $roleid
2007-09-19 07:02:57 +00:00
* @ return array
2007-03-07 13:45:41 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_role_access ( $roleid ) {
2016-05-14 21:14:31 +09:30
$accessdata = get_empty_accessdata ();
$accessdata [ 'ra' ][ '/' . SYSCONTEXTID ] = array (( int ) $roleid => ( int ) $roleid );
return $accessdata ;
}
2007-03-07 13:45:41 +00:00
2016-05-14 21:14:31 +09:30
/**
* Fetch raw " site wide " role definitions .
2017-03-27 11:44:43 +01:00
* Even MUC static acceleration cache appears a bit slow for this .
* Important as can be hit hundreds of times per page .
2016-05-14 21:14:31 +09:30
*
* @ param array $roleids List of role ids to fetch definitions for .
* @ return array Complete definition for each requested role .
*/
2017-03-27 11:44:43 +01:00
function get_role_definitions ( array $roleids ) {
global $ACCESSLIB_PRIVATE ;
2016-05-14 21:14:31 +09:30
if ( empty ( $roleids )) {
return array ();
}
2006-09-12 06:15:33 +00:00
2017-03-27 11:44:43 +01:00
// Grab all keys we have not yet got in our static cache.
if ( $uncached = array_diff ( $roleids , array_keys ( $ACCESSLIB_PRIVATE -> cacheroledefs ))) {
$cache = cache :: make ( 'core' , 'roledefs' );
2018-06-19 14:42:26 +01:00
foreach ( $cache -> get_many ( $uncached ) as $roleid => $cachedroledef ) {
if ( is_array ( $cachedroledef )) {
$ACCESSLIB_PRIVATE -> cacheroledefs [ $roleid ] = $cachedroledef ;
}
}
2012-09-28 11:39:41 +02:00
2017-03-27 11:44:43 +01:00
// Check we have the remaining keys from the MUC.
if ( $uncached = array_diff ( $roleids , array_keys ( $ACCESSLIB_PRIVATE -> cacheroledefs ))) {
$uncached = get_role_definitions_uncached ( $uncached );
$ACCESSLIB_PRIVATE -> cacheroledefs += $uncached ;
$cache -> set_many ( $uncached );
}
2016-05-14 21:14:31 +09:30
}
2012-09-28 11:39:41 +02:00
2017-03-27 11:44:43 +01:00
// Return just the roles we need.
return array_intersect_key ( $ACCESSLIB_PRIVATE -> cacheroledefs , array_flip ( $roleids ));
2016-05-14 21:14:31 +09:30
}
/**
* Query raw " site wide " role definitions .
*
* @ param array $roleids List of role ids to fetch definitions for .
* @ return array Complete definition for each requested role .
*/
function get_role_definitions_uncached ( array $roleids ) {
global $DB ;
if ( empty ( $roleids )) {
return array ();
2007-01-28 20:52:57 +00:00
}
2007-09-19 07:02:57 +00:00
2018-06-19 14:42:26 +01:00
// Create a blank results array: even if a role has no capabilities,
// we need to ensure it is included in the results to show we have
// loaded all the capabilities that there are.
2016-05-14 21:14:31 +09:30
$rdefs = array ();
2018-06-19 14:42:26 +01:00
foreach ( $roleids as $roleid ) {
$rdefs [ $roleid ] = array ();
}
2016-05-14 21:14:31 +09:30
2018-06-19 14:42:26 +01:00
// Load all the capabilities for these roles in all contexts.
list ( $sql , $params ) = $DB -> get_in_or_equal ( $roleids );
2016-05-14 21:14:31 +09:30
$sql = " SELECT ctx.path, rc.roleid, rc.capability, rc.permission
2017-03-27 11:44:43 +01:00
FROM { role_capabilities } rc
JOIN { context } ctx ON rc . contextid = ctx . id
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2017-09-06 16:59:12 +02:00
WHERE rc . roleid $sql " ;
2016-05-14 21:14:31 +09:30
$rs = $DB -> get_recordset_sql ( $sql , $params );
2018-06-19 14:42:26 +01:00
// Store the capabilities into the expected data structure.
2016-05-14 21:14:31 +09:30
foreach ( $rs as $rd ) {
if ( ! isset ( $rdefs [ $rd -> roleid ][ $rd -> path ])) {
$rdefs [ $rd -> roleid ][ $rd -> path ] = array ();
2007-09-26 07:12:38 +00:00
}
2016-05-14 21:14:31 +09:30
$rdefs [ $rd -> roleid ][ $rd -> path ][ $rd -> capability ] = ( int ) $rd -> permission ;
2007-09-26 07:12:38 +00:00
}
2016-05-14 21:14:31 +09:30
$rs -> close ();
2017-09-06 16:59:12 +02:00
// Sometimes (e.g. get_user_capability_course_helper::get_capability_info_at_each_context)
// we process role definitinons in a way that requires we see parent contexts
// before child contexts. This sort ensures that works (and is faster than
// sorting in the SQL query).
foreach ( $rdefs as $roleid => $rdef ) {
ksort ( $rdefs [ $roleid ]);
}
2016-05-14 21:14:31 +09:30
return $rdefs ;
2007-09-26 07:12:38 +00:00
}
2006-09-14 09:39:23 +00:00
/**
2011-10-14 12:48:00 +02:00
* Get the default guest role , this is used for guest account ,
* search engine spiders , etc .
2009-11-01 11:31:16 +00:00
*
2011-10-14 12:48:00 +02:00
* @ return stdClass role record
2006-09-14 09:39:23 +00:00
*/
function get_guest_role () {
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-02-01 10:24:26 +00:00
if ( empty ( $CFG -> guestroleid )) {
2010-03-31 07:41:31 +00:00
if ( $roles = $DB -> get_records ( 'role' , array ( 'archetype' => 'guest' ))) {
2007-02-01 10:24:26 +00:00
$guestrole = array_shift ( $roles ); // Pick the first one
set_config ( 'guestroleid' , $guestrole -> id );
return $guestrole ;
} else {
debugging ( 'Can not find any guest role!' );
return false ;
}
2006-09-14 09:39:23 +00:00
} else {
2008-05-15 21:40:00 +00:00
if ( $guestrole = $DB -> get_record ( 'role' , array ( 'id' => $CFG -> guestroleid ))) {
2007-02-01 10:24:26 +00:00
return $guestrole ;
} else {
2011-10-14 12:48:00 +02:00
// somebody is messing with guest roles, remove incorrect setting and try to find a new one
2007-02-01 10:24:26 +00:00
set_config ( 'guestroleid' , '' );
return get_guest_role ();
}
2006-09-14 09:39:23 +00:00
}
}
2007-10-09 12:49:54 +00:00
/**
2010-05-22 18:46:43 +00:00
* Check whether a user has a particular capability in a given context .
2009-05-19 07:50:54 +00:00
*
2011-10-14 12:48:00 +02:00
* For example :
2012-01-14 19:12:43 +01:00
* $context = context_module :: instance ( $cm -> id );
* has_capability ( 'mod/forum:replypost' , $context )
2009-05-19 07:50:54 +00:00
*
2010-05-22 18:46:43 +00:00
* By default checks the capabilities of the current user , but you can pass a
2010-03-31 07:41:31 +00:00
* different userid . By default will return true for admin users , but you can override that with the fourth argument .
*
* Guest and not - logged - in users can never get any dangerous capability - that is any write capability
* or capabilities with XSS , config or data loss risks .
2009-11-01 11:31:16 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2009-07-21 06:24:44 +00:00
* @ param string $capability the name of the capability to check . For example mod / forum : view
2012-01-14 19:12:43 +01:00
* @ param context $context the context to check the capability in . You normally get this with instance method of a context class .
* @ param integer | stdClass $user A user id or object . By default ( null ) checks the permissions of the current user .
2010-03-31 07:41:31 +00:00
* @ param boolean $doanything If false , ignores effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has this capability . Otherwise false .
2007-10-09 12:49:54 +00:00
*/
2011-10-14 12:48:00 +02:00
function has_capability ( $capability , context $context , $user = null , $doanything = true ) {
global $USER , $CFG , $SCRIPT , $ACCESSLIB_PRIVATE ;
2009-01-15 22:09:57 +00:00
2009-06-24 09:17:56 +00:00
if ( during_initial_install ()) {
2016-11-17 13:07:09 +08:00
if ( $SCRIPT === " / $CFG->admin /index.php "
or $SCRIPT === " / $CFG->admin /cli/install.php "
or $SCRIPT === " / $CFG->admin /cli/install_database.php "
or ( defined ( 'BEHAT_UTIL' ) and BEHAT_UTIL )
or ( defined ( 'PHPUNIT_UTIL' ) and PHPUNIT_UTIL )) {
2009-01-15 22:09:57 +00:00
// we are in an installer - roles can not work yet
return true ;
} else {
return false ;
}
}
2007-09-19 07:02:31 +00:00
2010-03-31 07:41:31 +00:00
if ( strpos ( $capability , 'moodle/legacy:' ) === 0 ) {
throw new coding_exception ( 'Legacy capabilities can not be used any more!' );
}
2011-10-14 12:48:00 +02:00
if ( ! is_bool ( $doanything )) {
throw new coding_exception ( 'Capability parameter "doanything" is wierd, only true or false is allowed. This has to be fixed in code.' );
}
// capability must exist
if ( ! $capinfo = get_capability_info ( $capability )) {
debugging ( 'Capability "' . $capability . '" was not found! This has to be fixed in code.' );
2007-10-05 15:06:38 +00:00
return false ;
2007-09-19 07:02:44 +00:00
}
2011-10-14 12:48:00 +02:00
if ( ! isset ( $USER -> id )) {
// should never happen
$USER -> id = 0 ;
2012-10-26 10:43:39 +08:00
debugging ( 'Capability check being performed on a user with no ID.' , DEBUG_DEVELOPER );
2010-03-31 07:41:31 +00:00
}
2007-09-19 07:02:31 +00:00
2010-03-31 07:41:31 +00:00
// make sure there is a real user specified
2010-10-01 21:45:14 +00:00
if ( $user === null ) {
2011-10-14 12:48:00 +02:00
$userid = $USER -> id ;
2010-03-31 07:41:31 +00:00
} else {
2011-07-24 15:04:17 +02:00
$userid = is_object ( $user ) ? $user -> id : $user ;
2008-01-08 15:04:00 +00:00
}
2011-10-14 12:48:00 +02:00
// make sure forcelogin cuts off not-logged-in users if enabled
if ( ! empty ( $CFG -> forcelogin ) and $userid == 0 ) {
2010-03-31 07:41:31 +00:00
return false ;
}
2011-10-14 12:48:00 +02:00
2010-03-31 07:41:31 +00:00
// make sure the guest account and not-logged-in users never get any risky caps no matter what the actual settings are.
2011-10-14 12:48:00 +02:00
if (( $capinfo -> captype === 'write' ) or ( $capinfo -> riskbitmask & ( RISK_XSS | RISK_CONFIG | RISK_DATALOSS ))) {
2010-03-31 07:41:31 +00:00
if ( isguestuser ( $userid ) or $userid == 0 ) {
return false ;
2009-06-29 05:00:45 +00:00
}
2007-09-19 07:02:31 +00:00
}
2018-06-07 14:35:26 +08:00
// Check whether context locking is enabled.
if ( ! empty ( $CFG -> contextlocking )) {
2018-11-13 09:14:34 +08:00
if ( $capinfo -> captype === 'write' && $context -> locked ) {
// Context locking applies to any write capability in a locked context.
// It does not apply to moodle/site:managecontextlocks - this is to allow context locking to be unlocked.
if ( $capinfo -> name !== 'moodle/site:managecontextlocks' ) {
// It applies to all users who are not site admins.
// It also applies to site admins when contextlockappliestoadmin is set.
if ( ! is_siteadmin ( $userid ) || ! empty ( $CFG -> contextlockappliestoadmin )) {
return false ;
}
}
2018-06-07 14:35:26 +08:00
}
}
2011-10-14 12:48:00 +02:00
// somehow make sure the user is not deleted and actually exists
if ( $userid != 0 ) {
if ( $userid == $USER -> id and isset ( $USER -> deleted )) {
// this prevents one query per page, it is a bit of cheating,
// but hopefully session is terminated properly once user is deleted
if ( $USER -> deleted ) {
return false ;
}
2007-10-09 12:49:54 +00:00
} else {
2011-10-14 12:48:00 +02:00
if ( ! context_user :: instance ( $userid , IGNORE_MISSING )) {
// no user context == invalid userid
return false ;
}
2007-11-16 03:34:05 +00:00
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
2011-10-14 12:48:00 +02:00
// context path/depth must be valid
if ( empty ( $context -> path ) or $context -> depth == 0 ) {
// this should not happen often, each upgrade tries to rebuild the context paths
2015-07-10 01:59:31 +02:00
debugging ( 'Context id ' . $context -> id . ' does not have valid path, please use context_helper::build_all_paths()' );
2011-10-14 12:48:00 +02:00
if ( is_siteadmin ( $userid )) {
return true ;
2007-10-09 12:49:54 +00:00
} else {
2011-10-14 12:48:00 +02:00
return false ;
2007-10-09 12:49:54 +00:00
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
2020-07-20 12:28:35 +08:00
if ( ! empty ( $USER -> loginascontext )) {
// The current user is logged in as another user and can assume their identity at or below the `loginascontext`
// defined in the USER session.
// The user may not assume their identity at any other location.
if ( ! $USER -> loginascontext -> is_parent_of ( $context , true )) {
// The context being checked is not the specified context, or one of its children.
return false ;
}
}
2010-03-31 07:41:31 +00:00
// Find out if user is admin - it is not possible to override the doanything in any way
// and it is not possible to switch to admin role either.
if ( $doanything ) {
if ( is_siteadmin ( $userid )) {
2010-07-07 08:21:51 +00:00
if ( $userid != $USER -> id ) {
return true ;
}
// make sure switchrole is not used in this context
if ( empty ( $USER -> access [ 'rsw' ])) {
return true ;
}
$parts = explode ( '/' , trim ( $context -> path , '/' ));
$path = '' ;
$switched = false ;
foreach ( $parts as $part ) {
$path .= '/' . $part ;
if ( ! empty ( $USER -> access [ 'rsw' ][ $path ])) {
$switched = true ;
break ;
}
}
if ( ! $switched ) {
return true ;
}
//ok, admin switched role in this context, let's use normal access control rules
2010-03-31 07:41:31 +00:00
}
}
2011-10-14 12:48:00 +02:00
// Careful check for staleness...
$context -> reload_if_dirty ();
2007-09-19 07:03:34 +00:00
2011-10-14 12:48:00 +02:00
if ( $USER -> id == $userid ) {
if ( ! isset ( $USER -> access )) {
load_all_capabilities ();
2007-09-19 07:02:31 +00:00
}
2011-10-14 12:48:00 +02:00
$access =& $USER -> access ;
2007-09-20 04:52:54 +00:00
2011-10-14 12:48:00 +02:00
} else {
// make sure user accessdata is really loaded
get_user_accessdata ( $userid , true );
$access =& $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ];
2007-09-19 07:06:55 +00:00
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
return has_capability_in_accessdata ( $capability , $context , $access );
2007-09-19 07:02:31 +00:00
}
2007-10-30 10:50:20 +00:00
/**
2009-07-21 06:24:44 +00:00
* Check if the user has any one of several capabilities from a list .
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* This is just a utility method that calls has_capability in a loop . Try to put
* the capabilities that most users are likely to have first in the list for best
* performance .
2007-10-30 10:50:20 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
2012-01-14 19:12:43 +01:00
*
2009-07-21 06:24:44 +00:00
* @ param array $capabilities an array of capability names .
2012-01-14 19:12:43 +01:00
* @ param context $context the context to check the capability in . You normally get this with instance method of a context class .
* @ param integer | stdClass $user A user id or object . By default ( null ) checks the permissions of the current user .
2010-03-31 07:41:31 +00:00
* @ param boolean $doanything If false , ignore effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has any of these capabilities . Otherwise false .
2007-10-30 10:50:20 +00:00
*/
2012-01-14 19:12:43 +01:00
function has_any_capability ( array $capabilities , context $context , $user = null , $doanything = true ) {
2007-10-30 10:50:20 +00:00
foreach ( $capabilities as $capability ) {
2012-01-14 19:12:43 +01:00
if ( has_capability ( $capability , $context , $user , $doanything )) {
2007-10-30 10:50:20 +00:00
return true ;
}
}
return false ;
}
2008-12-08 07:28:19 +00:00
/**
2009-07-21 06:24:44 +00:00
* Check if the user has all the capabilities in a list .
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* This is just a utility method that calls has_capability in a loop . Try to put
* the capabilities that fewest users are likely to have first in the list for best
* performance .
2008-12-08 07:28:19 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
2012-01-14 19:12:43 +01:00
*
2009-07-21 06:24:44 +00:00
* @ param array $capabilities an array of capability names .
2012-01-14 19:12:43 +01:00
* @ param context $context the context to check the capability in . You normally get this with instance method of a context class .
* @ param integer | stdClass $user A user id or object . By default ( null ) checks the permissions of the current user .
2010-03-31 07:41:31 +00:00
* @ param boolean $doanything If false , ignore effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has all of these capabilities . Otherwise false .
2008-12-08 07:28:19 +00:00
*/
2012-01-14 19:12:43 +01:00
function has_all_capabilities ( array $capabilities , context $context , $user = null , $doanything = true ) {
2008-12-08 07:28:19 +00:00
foreach ( $capabilities as $capability ) {
2012-01-14 19:12:43 +01:00
if ( ! has_capability ( $capability , $context , $user , $doanything )) {
2008-12-08 07:28:19 +00:00
return false ;
}
}
return true ;
}
2013-07-21 11:47:40 +02:00
/**
* Is course creator going to have capability in a new course ?
*
* This is intended to be used in enrolment plugins before or during course creation ,
* do not use after the course is fully created .
*
* @ category access
*
* @ param string $capability the name of the capability to check .
* @ param context $context course or category context where is course going to be created
* @ param integer | stdClass $user A user id or object . By default ( null ) checks the permissions of the current user .
* @ return boolean true if the user will have this capability .
*
2013-07-23 15:59:02 +02:00
* @ throws coding_exception if different type of context submitted
2013-07-21 11:47:40 +02:00
*/
2013-07-23 15:55:07 +02:00
function guess_if_creator_will_have_course_capability ( $capability , context $context , $user = null ) {
2013-07-21 11:47:40 +02:00
global $CFG ;
if ( $context -> contextlevel != CONTEXT_COURSE and $context -> contextlevel != CONTEXT_COURSECAT ) {
throw new coding_exception ( 'Only course or course category context expected' );
}
if ( has_capability ( $capability , $context , $user )) {
// User already has the capability, it could be only removed if CAP_PROHIBIT
// was involved here, but we ignore that.
return true ;
}
if ( ! has_capability ( 'moodle/course:create' , $context , $user )) {
return false ;
}
if ( ! enrol_is_enabled ( 'manual' )) {
return false ;
}
if ( empty ( $CFG -> creatornewroleid )) {
return false ;
}
if ( $context -> contextlevel == CONTEXT_COURSE ) {
if ( is_viewing ( $context , $user , 'moodle/role:assign' ) or is_enrolled ( $context , $user , 'moodle/role:assign' )) {
return false ;
}
} else {
if ( has_capability ( 'moodle/course:view' , $context , $user ) and has_capability ( 'moodle/role:assign' , $context , $user )) {
return false ;
}
}
// Most likely they will be enrolled after the course creation is finished,
// does the new role have the required capability?
list ( $neededroles , $forbiddenroles ) = get_roles_with_cap_in_context ( $context , $capability );
return isset ( $neededroles [ $CFG -> creatornewroleid ]);
}
2007-10-09 12:49:54 +00:00
/**
2010-03-31 07:41:31 +00:00
* Check if the user is an admin at the site level .
2009-05-19 07:50:54 +00:00
*
2010-03-31 07:41:31 +00:00
* Please note that use of proper capabilities is always encouraged ,
* this function is supposed to be used from core or for temporary hacks .
2007-09-19 07:30:09 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2011-10-14 12:48:00 +02:00
* @ param int | stdClass $user_or_id user id or user object
* @ return bool true if user is one of the administrators , false otherwise
2007-09-19 07:30:09 +00:00
*/
2010-10-01 21:45:14 +00:00
function is_siteadmin ( $user_or_id = null ) {
2010-03-31 07:41:31 +00:00
global $CFG , $USER ;
2007-09-19 07:30:09 +00:00
2010-10-01 21:45:14 +00:00
if ( $user_or_id === null ) {
2010-03-31 07:41:31 +00:00
$user_or_id = $USER ;
}
2008-10-30 10:49:15 +00:00
2010-03-31 07:41:31 +00:00
if ( empty ( $user_or_id )) {
return false ;
}
if ( ! empty ( $user_or_id -> id )) {
$userid = $user_or_id -> id ;
} else {
$userid = $user_or_id ;
}
2008-10-30 10:49:15 +00:00
2013-05-01 18:44:55 +01:00
// Because this script is called many times (150+ for course page) with
// the same parameters, it is worth doing minor optimisations. This static
// cache stores the value for a single userid, saving about 2ms from course
// page load time without using significant memory. As the static cache
// also includes the value it depends on, this cannot break unit tests.
static $knownid , $knownresult , $knownsiteadmins ;
if ( $knownid === $userid && $knownsiteadmins === $CFG -> siteadmins ) {
return $knownresult ;
}
$knownid = $userid ;
$knownsiteadmins = $CFG -> siteadmins ;
2010-03-31 07:41:31 +00:00
$siteadmins = explode ( ',' , $CFG -> siteadmins );
2013-05-01 18:44:55 +01:00
$knownresult = in_array ( $userid , $siteadmins );
return $knownresult ;
2008-10-30 10:49:15 +00:00
}
2008-11-18 07:10:00 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns true if user has at least one role assign
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
* of 'coursecontact' role ( is potentially listed in some course descriptions ) .
2010-10-01 21:45:14 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $userid
* @ return bool
2008-11-18 07:10:00 +00:00
*/
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
function has_coursecontact_role ( $userid ) {
2010-09-17 07:39:14 +00:00
global $DB , $CFG ;
2008-11-18 07:10:00 +00:00
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
if ( empty ( $CFG -> coursecontact )) {
2010-03-31 07:41:31 +00:00
return false ;
}
$sql = " SELECT 1
FROM { role_assignments }
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
WHERE userid = : userid AND roleid IN ( $CFG -> coursecontact ) " ;
2010-09-19 13:30:05 +00:00
return $DB -> record_exists_sql ( $sql , array ( 'userid' => $userid ));
2008-11-18 07:10:00 +00:00
}
2007-10-09 12:49:54 +00:00
/**
2010-03-07 09:28:54 +00:00
* Does the user have a capability to do something ?
2009-05-19 07:50:54 +00:00
*
2007-09-19 07:15:12 +00:00
* Walk the accessdata array and return true / false .
2011-10-14 12:48:00 +02:00
* Deals with prohibits , role switching , aggregating
2007-09-19 07:05:48 +00:00
* capabilities , etc .
*
* The main feature of here is being FAST and with no
2008-05-24 18:35:48 +00:00
* side effects .
2007-09-19 07:05:48 +00:00
*
2007-09-19 07:16:18 +00:00
* Notes :
*
2007-09-19 07:18:23 +00:00
* Switch Role merges with default role
* ------------------------------------
* If you are a teacher in course X , you have at least
* teacher - in - X + defaultloggedinuser - sitewide . So in the
* course you ' ll have techer + defaultloggedinuser .
* We try to mimic that in switchrole .
*
2010-03-07 09:28:54 +00:00
* Permission evaluation
* ---------------------
2010-05-22 18:46:43 +00:00
* Originally there was an extremely complicated way
2010-03-07 09:28:54 +00:00
* to determine the user access that dealt with
2010-05-22 18:46:43 +00:00
* " locality " or role assignments and role overrides .
* Now we simply evaluate access for each role separately
2010-03-07 09:28:54 +00:00
* and then verify if user has at least one role with allow
* and at the same time no role with prohibit .
*
2012-01-14 19:12:43 +01:00
* @ access private
2009-05-19 07:50:54 +00:00
* @ param string $capability
2011-10-14 12:48:00 +02:00
* @ param context $context
2009-05-19 07:50:54 +00:00
* @ param array $accessdata
* @ return bool
2007-09-19 07:05:48 +00:00
*/
2011-10-14 12:48:00 +02:00
function has_capability_in_accessdata ( $capability , context $context , array & $accessdata ) {
2007-09-19 07:16:18 +00:00
global $CFG ;
2010-03-07 09:28:54 +00:00
// Build $paths as a list of current + all parent "paths" with order bottom-to-top
2011-10-14 12:48:00 +02:00
$path = $context -> path ;
$paths = array ( $path );
2020-05-06 09:14:49 +01:00
while ( $path = rtrim ( $path , '0123456789' )) {
2011-10-14 12:48:00 +02:00
$path = rtrim ( $path , '/' );
if ( $path === '' ) {
break ;
}
$paths [] = $path ;
2007-09-19 07:16:18 +00:00
}
2010-03-07 09:28:54 +00:00
$roles = array ();
$switchedrole = false ;
2007-09-19 07:05:48 +00:00
2010-03-07 09:28:54 +00:00
// Find out if role switched
if ( ! empty ( $accessdata [ 'rsw' ])) {
2007-09-19 07:05:48 +00:00
// From the bottom up...
2010-03-07 09:28:54 +00:00
foreach ( $paths as $path ) {
2010-03-24 13:10:10 +00:00
if ( isset ( $accessdata [ 'rsw' ][ $path ])) {
2010-03-07 09:28:54 +00:00
// Found a switchrole assignment - check for that role _plus_ the default user role
2010-10-01 21:45:14 +00:00
$roles = array ( $accessdata [ 'rsw' ][ $path ] => null , $CFG -> defaultuserroleid => null );
2010-03-07 09:28:54 +00:00
$switchedrole = true ;
break ;
2007-09-19 07:05:48 +00:00
}
}
}
2010-03-07 09:28:54 +00:00
if ( ! $switchedrole ) {
// get all users roles in this context and above
foreach ( $paths as $path ) {
if ( isset ( $accessdata [ 'ra' ][ $path ])) {
foreach ( $accessdata [ 'ra' ][ $path ] as $roleid ) {
2010-10-01 21:45:14 +00:00
$roles [ $roleid ] = null ;
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
}
}
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
// Now find out what access is given to each role, going bottom-->up direction
2016-05-14 21:14:31 +09:30
$rdefs = get_role_definitions ( array_keys ( $roles ));
2011-10-14 12:48:00 +02:00
$allowed = false ;
2016-05-14 21:14:31 +09:30
2010-03-07 09:28:54 +00:00
foreach ( $roles as $roleid => $ignored ) {
foreach ( $paths as $path ) {
2016-05-14 21:14:31 +09:30
if ( isset ( $rdefs [ $roleid ][ $path ][ $capability ])) {
$perm = ( int ) $rdefs [ $roleid ][ $path ][ $capability ];
2011-10-14 12:48:00 +02:00
if ( $perm === CAP_PROHIBIT ) {
// any CAP_PROHIBIT found means no permission for the user
return false ;
}
if ( is_null ( $roles [ $roleid ])) {
2010-03-07 09:28:54 +00:00
$roles [ $roleid ] = $perm ;
}
}
2007-09-19 07:02:31 +00:00
}
2011-10-14 12:48:00 +02:00
// CAP_ALLOW in any role means the user has a permission, we continue only to detect prohibits
$allowed = ( $allowed or $roles [ $roleid ] === CAP_ALLOW );
2007-09-19 07:02:31 +00:00
}
2011-10-14 12:48:00 +02:00
return $allowed ;
2007-09-19 07:03:19 +00:00
}
2006-08-14 05:55:40 +00:00
/**
2009-07-21 06:24:44 +00:00
* A convenience function that tests has_capability , and displays an error if
* the user does not have that capability .
2009-07-04 14:22:11 +00:00
*
2009-07-21 06:24:44 +00:00
* NOTE before Moodle 2.0 , this function attempted to make an appropriate
* require_login call before checking the capability . This is no longer the case .
* You must call require_login ( or one of its variants ) if you want to check the
* user is logged in , before you call this function .
2007-09-19 07:24:43 +00:00
*
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
*
2009-07-21 06:24:44 +00:00
* @ param string $capability the name of the capability to check . For example mod / forum : view
2013-07-01 14:03:35 +08:00
* @ param context $context the context to check the capability in . You normally get this with context_xxxx :: instance () .
2011-10-14 12:48:00 +02:00
* @ param int $userid A user id . By default ( null ) checks the permissions of the current user .
2010-03-31 07:41:31 +00:00
* @ param bool $doanything If false , ignore effect of admin role assignment
2011-10-14 12:48:00 +02:00
* @ param string $errormessage The error string to to user . Defaults to 'nopermissions' .
2009-07-21 06:24:44 +00:00
* @ param string $stringfile The language file to load the error string from . Defaults to 'error' .
* @ return void terminates with an error if the user does not have the given capability .
2006-08-14 05:55:40 +00:00
*/
2011-10-14 12:48:00 +02:00
function require_capability ( $capability , context $context , $userid = null , $doanything = true ,
2009-07-21 06:24:44 +00:00
$errormessage = 'nopermissions' , $stringfile = '' ) {
2006-09-13 06:35:25 +00:00
if ( ! has_capability ( $capability , $context , $userid , $doanything )) {
2009-09-14 23:52:08 +00:00
throw new required_capability_exception ( $context , $capability , $errormessage , $stringfile );
2006-08-14 05:55:40 +00:00
}
}
2020-03-02 04:24:19 +11:00
/**
* A convenience function that tests has_capability for a list of capabilities , and displays an error if
* the user does not have that capability .
*
* This is just a utility method that calls has_capability in a loop . Try to put
* the capabilities that fewest users are likely to have first in the list for best
* performance .
*
* @ category access
* @ see has_capability ()
*
* @ param array $capabilities an array of capability names .
* @ param context $context the context to check the capability in . You normally get this with context_xxxx :: instance () .
* @ param int $userid A user id . By default ( null ) checks the permissions of the current user .
* @ param bool $doanything If false , ignore effect of admin role assignment
* @ param string $errormessage The error string to to user . Defaults to 'nopermissions' .
* @ param string $stringfile The language file to load the error string from . Defaults to 'error' .
* @ return void terminates with an error if the user does not have the given capability .
*/
function require_all_capabilities ( array $capabilities , context $context , $userid = null , $doanything = true ,
$errormessage = 'nopermissions' , $stringfile = '' ) : void {
foreach ( $capabilities as $capability ) {
if ( ! has_capability ( $capability , $context , $userid , $doanything )) {
throw new required_capability_exception ( $context , $capability , $errormessage , $stringfile );
}
}
}
2007-09-19 07:02:04 +00:00
/**
2016-05-14 21:14:31 +09:30
* Return a nested array showing all role assignments for the user .
* [ ra ] => [ contextpath ][ roleid ] = roleid
2007-09-19 07:02:04 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2010-10-01 21:45:14 +00:00
* @ param int $userid - the id of the user
2011-10-14 12:48:00 +02:00
* @ return array access info array
2007-09-19 07:02:04 +00:00
*/
2016-05-14 21:14:31 +09:30
function get_user_roles_sitewide_accessdata ( $userid ) {
2017-03-27 11:44:43 +01:00
global $CFG , $DB ;
2007-09-19 07:02:04 +00:00
2011-10-14 12:48:00 +02:00
$accessdata = get_empty_accessdata ();
2007-09-19 07:02:04 +00:00
2011-10-14 12:48:00 +02:00
// start with the default role
if ( ! empty ( $CFG -> defaultuserroleid )) {
$syscontext = context_system :: instance ();
$accessdata [ 'ra' ][ $syscontext -> path ][( int ) $CFG -> defaultuserroleid ] = ( int ) $CFG -> defaultuserroleid ;
}
// load the "default frontpage role"
if ( ! empty ( $CFG -> defaultfrontpageroleid )) {
$frontpagecontext = context_course :: instance ( get_site () -> id );
if ( $frontpagecontext -> path ) {
$accessdata [ 'ra' ][ $frontpagecontext -> path ][( int ) $CFG -> defaultfrontpageroleid ] = ( int ) $CFG -> defaultfrontpageroleid ;
}
}
2016-05-14 21:14:31 +09:30
// Preload every assigned role.
2011-12-16 14:22:25 +01:00
$sql = " SELECT ctx.path, ra.roleid, ra.contextid
2017-03-27 11:44:43 +01:00
FROM { role_assignments } ra
JOIN { context } ctx ON ctx . id = ra . contextid
WHERE ra . userid = : userid " ;
2016-05-14 21:14:31 +09:30
$rs = $DB -> get_recordset_sql ( $sql , array ( 'userid' => $userid ));
2011-10-14 12:48:00 +02:00
foreach ( $rs as $ra ) {
// RAs leafs are arrays to support multi-role assignments...
$accessdata [ 'ra' ][ $ra -> path ][( int ) $ra -> roleid ] = ( int ) $ra -> roleid ;
2007-09-19 07:02:04 +00:00
}
2011-10-14 12:48:00 +02:00
$rs -> close ();
2007-09-19 07:02:04 +00:00
2007-09-20 04:52:54 +00:00
return $accessdata ;
2007-09-19 07:02:04 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns empty accessdata structure .
2011-10-25 14:20:22 +02:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ return array empt accessdata
*/
function get_empty_accessdata () {
$accessdata = array (); // named list
$accessdata [ 'ra' ] = array ();
$accessdata [ 'time' ] = time ();
2012-01-15 00:14:44 +01:00
$accessdata [ 'rsw' ] = array ();
2011-10-14 12:48:00 +02:00
2007-09-20 04:52:54 +00:00
return $accessdata ;
2007-09-19 07:05:32 +00:00
}
2007-10-17 09:19:39 +00:00
/**
2011-10-14 12:48:00 +02:00
* Get accessdata for a given user .
2007-09-19 07:06:55 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2009-05-19 07:50:54 +00:00
* @ param int $userid
2011-10-14 12:48:00 +02:00
* @ param bool $preloadonly true means do not return access array
* @ return array accessdata
2008-05-24 18:35:48 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_user_accessdata ( $userid , $preloadonly = false ) {
global $CFG , $ACCESSLIB_PRIVATE , $USER ;
2007-09-19 07:06:55 +00:00
2016-05-14 21:14:31 +09:30
if ( isset ( $USER -> access )) {
2013-11-25 20:08:36 +13:00
$ACCESSLIB_PRIVATE -> accessdatabyuser [ $USER -> id ] = $USER -> access ;
2007-09-19 07:06:55 +00:00
}
2011-10-14 12:48:00 +02:00
if ( ! isset ( $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ])) {
if ( empty ( $userid )) {
if ( ! empty ( $CFG -> notloggedinroleid )) {
$accessdata = get_role_access ( $CFG -> notloggedinroleid );
} else {
// weird
return get_empty_accessdata ();
}
} else if ( isguestuser ( $userid )) {
if ( $guestrole = get_guest_role ()) {
$accessdata = get_role_access ( $guestrole -> id );
} else {
//weird
return get_empty_accessdata ();
}
} else {
2017-03-27 11:44:43 +01:00
// Includes default role and frontpage role.
$accessdata = get_user_roles_sitewide_accessdata ( $userid );
2007-09-26 07:12:38 +00:00
}
2007-10-09 12:49:54 +00:00
2011-10-14 12:48:00 +02:00
$ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ] = $accessdata ;
}
2007-10-17 09:19:39 +00:00
2011-10-14 12:48:00 +02:00
if ( $preloadonly ) {
return ;
} else {
return $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ];
}
2007-09-19 07:06:55 +00:00
}
2007-09-19 07:11:18 +00:00
2007-09-19 07:05:32 +00:00
/**
2009-05-19 07:50:54 +00:00
* A convenience function to completely load all the capabilities
2011-10-14 12:48:00 +02:00
* for the current user . It is called from has_capability () and functions change permissions .
*
* Call it only _after_ you ' ve setup $USER and called check_enrolment_plugins ();
2009-05-19 07:50:54 +00:00
* @ see check_enrolment_plugins ()
2009-11-01 11:31:16 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2010-10-01 21:45:14 +00:00
* @ return void
2006-10-23 15:17:31 +00:00
*/
function load_all_capabilities () {
2011-10-14 12:48:00 +02:00
global $USER ;
2006-08-08 05:13:06 +00:00
2009-01-15 22:09:57 +00:00
// roles not installed yet - we are in the middle of installation
2009-06-24 09:17:56 +00:00
if ( during_initial_install ()) {
2009-01-12 16:52:53 +00:00
return ;
}
2011-10-14 12:48:00 +02:00
if ( ! isset ( $USER -> id )) {
// this should not happen
$USER -> id = 0 ;
2006-10-23 15:17:31 +00:00
}
2007-09-19 07:17:08 +00:00
2011-10-14 12:48:00 +02:00
unset ( $USER -> access );
$USER -> access = get_user_accessdata ( $USER -> id );
2007-09-19 07:17:08 +00:00
// Clear to force a refresh
2011-10-14 12:48:00 +02:00
unset ( $USER -> mycourses );
2011-11-05 12:12:48 +01:00
// init/reset internal enrol caches - active course enrolments and temp access
$USER -> enrol = array ( 'enrolled' => array (), 'tempguest' => array ());
2006-08-08 05:13:06 +00:00
}
2007-09-19 07:11:18 +00:00
/**
2008-05-24 18:35:48 +00:00
* A convenience function to completely reload all the capabilities
2007-09-19 07:11:18 +00:00
* for the current user when roles have been updated in a relevant
2008-05-24 18:35:48 +00:00
* context -- but PRESERVING switchroles and loginas .
2011-10-14 12:48:00 +02:00
* This function resets all accesslib and context caches .
2007-09-19 07:11:18 +00:00
*
* That is - completely transparent to the user .
2008-05-24 18:35:48 +00:00
*
2011-10-14 12:48:00 +02:00
* Note : reloads $USER -> access completely .
2007-09-19 07:11:18 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2010-10-01 21:45:14 +00:00
* @ return void
2007-09-19 07:11:18 +00:00
*/
function reload_all_capabilities () {
2011-10-14 12:48:00 +02:00
global $USER , $DB , $ACCESSLIB_PRIVATE ;
2007-09-19 07:11:18 +00:00
// copy switchroles
$sw = array ();
2012-01-15 00:14:44 +01:00
if ( ! empty ( $USER -> access [ 'rsw' ])) {
2007-09-19 07:11:18 +00:00
$sw = $USER -> access [ 'rsw' ];
}
2011-10-14 12:48:00 +02:00
accesslib_clear_all_caches ( true );
2007-09-19 07:11:18 +00:00
unset ( $USER -> access );
2018-06-05 16:37:25 -04:00
// Prevent dirty flags refetching on this page.
$ACCESSLIB_PRIVATE -> dirtycontexts = array ();
$ACCESSLIB_PRIVATE -> dirtyusers = array ( $USER -> id => false );
2008-05-24 18:35:48 +00:00
2007-09-19 07:11:18 +00:00
load_all_capabilities ();
foreach ( $sw as $path => $roleid ) {
2011-10-14 12:48:00 +02:00
if ( $record = $DB -> get_record ( 'context' , array ( 'path' => $path ))) {
$context = context :: instance_by_id ( $record -> id );
2018-09-26 13:03:08 +02:00
if ( has_capability ( 'moodle/role:switchroles' , $context )) {
role_switch ( $roleid , $context );
}
2011-10-14 12:48:00 +02:00
}
2007-09-19 07:11:18 +00:00
}
}
2006-10-23 15:17:31 +00:00
2008-05-15 21:40:00 +00:00
/**
2011-10-14 12:48:00 +02:00
* Adds a temp role to current USER -> access array .
2007-09-19 07:16:29 +00:00
*
2011-10-14 12:48:00 +02:00
* Useful for the " temporary guest " access we grant to logged - in users .
2012-01-14 19:12:43 +01:00
* This is useful for enrol plugins only .
2007-09-19 07:16:29 +00:00
*
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-14 12:48:00 +02:00
* @ param context_course $coursecontext
2009-05-19 07:50:54 +00:00
* @ param int $roleid
2011-10-14 12:48:00 +02:00
* @ return void
2007-09-19 07:16:29 +00:00
*/
2011-10-14 12:48:00 +02:00
function load_temp_course_role ( context_course $coursecontext , $roleid ) {
2011-11-05 12:12:48 +01:00
global $USER , $SITE ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( empty ( $roleid )) {
debugging ( 'invalid role specified in load_temp_course_role()' );
return ;
}
2007-09-19 07:16:29 +00:00
2011-11-05 12:12:48 +01:00
if ( $coursecontext -> instanceid == $SITE -> id ) {
debugging ( 'Can not use temp roles on the frontpage' );
return ;
}
2011-10-14 12:48:00 +02:00
if ( ! isset ( $USER -> access )) {
load_all_capabilities ();
2008-05-15 21:40:00 +00:00
}
2007-09-19 07:16:29 +00:00
2011-10-14 12:48:00 +02:00
$coursecontext -> reload_if_dirty ();
2007-09-19 07:16:29 +00:00
2011-10-14 12:48:00 +02:00
if ( isset ( $USER -> access [ 'ra' ][ $coursecontext -> path ][ $roleid ])) {
return ;
2007-09-19 07:16:29 +00:00
}
2011-10-14 12:48:00 +02:00
$USER -> access [ 'ra' ][ $coursecontext -> path ][( int ) $roleid ] = ( int ) $roleid ;
2007-09-19 07:16:29 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2011-10-14 12:48:00 +02:00
* Removes any extra guest roles from current USER -> access array .
2012-01-14 19:12:43 +01:00
* This is useful for enrol plugins only .
2011-10-14 12:48:00 +02:00
*
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-14 12:48:00 +02:00
* @ param context_course $coursecontext
* @ return void
2006-09-16 13:54:57 +00:00
*/
2011-10-14 12:48:00 +02:00
function remove_temp_course_roles ( context_course $coursecontext ) {
2011-11-05 12:12:48 +01:00
global $DB , $USER , $SITE ;
if ( $coursecontext -> instanceid == $SITE -> id ) {
debugging ( 'Can not use temp roles on the frontpage' );
return ;
}
2011-10-14 12:48:00 +02:00
if ( empty ( $USER -> access [ 'ra' ][ $coursecontext -> path ])) {
//no roles here, weird
return ;
}
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
$sql = " SELECT DISTINCT ra.roleid AS id
FROM { role_assignments } ra
WHERE ra . contextid = : contextid AND ra . userid = : userid " ;
2011-10-14 12:48:00 +02:00
$ras = $DB -> get_records_sql ( $sql , array ( 'contextid' => $coursecontext -> id , 'userid' => $USER -> id ));
2006-09-25 01:34:21 +00:00
2011-10-14 12:48:00 +02:00
$USER -> access [ 'ra' ][ $coursecontext -> path ] = array ();
2020-05-06 09:14:49 +01:00
foreach ( $ras as $r ) {
2011-10-14 12:48:00 +02:00
$USER -> access [ 'ra' ][ $coursecontext -> path ][( int ) $r -> id ] = ( int ) $r -> id ;
2010-10-13 08:29:22 +00:00
}
2006-09-16 13:54:57 +00:00
}
2007-03-03 21:07:07 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns array of all role archetypes .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ return array
2007-03-03 21:07:07 +00:00
*/
2010-03-31 07:41:31 +00:00
function get_role_archetypes () {
2007-03-03 21:07:07 +00:00
return array (
2010-03-31 07:41:31 +00:00
'manager' => 'manager' ,
'coursecreator' => 'coursecreator' ,
'editingteacher' => 'editingteacher' ,
'teacher' => 'teacher' ,
'student' => 'student' ,
'guest' => 'guest' ,
'user' => 'user' ,
'frontpage' => 'frontpage'
2007-03-03 21:07:07 +00:00
);
}
2006-08-08 05:13:06 +00:00
/**
2010-05-22 18:46:43 +00:00
* Assign the defaults found in this capability definition to roles that have
2006-08-08 05:13:06 +00:00
* the corresponding legacy capabilities assigned to them .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param string $capability
* @ param array $legacyperms an array in the format ( example ) :
2006-08-08 05:13:06 +00:00
* 'guest' => CAP_PREVENT ,
* 'student' => CAP_ALLOW ,
* 'teacher' => CAP_ALLOW ,
* 'editingteacher' => CAP_ALLOW ,
* 'coursecreator' => CAP_ALLOW ,
2010-03-31 07:41:31 +00:00
* 'manager' => CAP_ALLOW
2009-05-19 07:50:54 +00:00
* @ return boolean success or failure .
2006-08-08 05:13:06 +00:00
*/
function assign_legacy_capabilities ( $capability , $legacyperms ) {
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
$archetypes = get_role_archetypes ();
2007-03-03 21:07:07 +00:00
2006-08-08 05:13:06 +00:00
foreach ( $legacyperms as $type => $perm ) {
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$systemcontext = context_system :: instance ();
2010-03-31 07:41:31 +00:00
if ( $type === 'admin' ) {
debugging ( 'Legacy type admin in access.php was renamed to manager, please update the code.' );
$type = 'manager' ;
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( ! array_key_exists ( $type , $archetypes )) {
2022-04-12 09:38:41 +05:30
throw new \moodle_exception ( 'invalidlegacy' , '' , '' , $type );
2007-03-03 21:07:07 +00:00
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( $roles = get_archetype_roles ( $type )) {
2006-09-12 07:07:30 +00:00
foreach ( $roles as $role ) {
// Assign a site level capability.
if ( ! assign_capability ( $capability , $perm , $role -> id , $systemcontext -> id )) {
return false ;
}
2006-08-08 05:13:06 +00:00
}
}
}
return true ;
}
2008-11-05 08:17:30 +00:00
/**
2011-10-14 12:48:00 +02:00
* Verify capability risks .
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $capability a capability - a row from the capabilities table .
2010-05-21 19:31:17 +00:00
* @ return boolean whether this capability is safe - that is , whether people with the
2008-11-05 08:17:30 +00:00
* safeoverrides capability should be allowed to change it .
*/
function is_safe_capability ( $capability ) {
2008-11-18 08:08:18 +00:00
return ! (( RISK_DATALOSS | RISK_MANAGETRUST | RISK_CONFIG | RISK_XSS | RISK_PERSONAL ) & $capability -> riskbitmask );
2008-11-05 08:17:30 +00:00
}
2006-08-14 07:15:03 +00:00
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Get the local override ( if any ) for a given capability in a role in a context
2010-06-04 07:30:42 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid
* @ param int $contextid
* @ param string $capability
* @ return stdClass local capability override
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_local_override ( $roleid , $contextid , $capability ) {
global $DB ;
2019-02-28 08:39:20 +08:00
return $DB -> get_record_sql ( "
SELECT rc .*
FROM { role_capabilities } rc
JOIN { capability } cap ON rc . capability = cap . name
WHERE rc . roleid = : roleid AND rc . capability = : capability AND rc . contextid = : contextid " , [
'roleid' => $roleid ,
'contextid' => $contextid ,
'capability' => $capability ,
]);
2011-10-14 12:48:00 +02:00
}
2007-09-19 07:13:08 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns context instance plus related course and cm instances
*
* @ param int $contextid
* @ return array of ( $context , $course , $cm )
*/
function get_context_info_array ( $contextid ) {
2013-08-21 13:42:30 +08:00
global $DB ;
2011-10-14 12:48:00 +02:00
$context = context :: instance_by_id ( $contextid , MUST_EXIST );
$course = null ;
$cm = null ;
2007-09-19 07:13:08 +00:00
2011-10-14 12:48:00 +02:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
2013-08-21 13:42:30 +08:00
$course = $DB -> get_record ( 'course' , array ( 'id' => $context -> instanceid ), '*' , MUST_EXIST );
2007-09-19 07:13:08 +00:00
2011-10-14 12:48:00 +02:00
} else if ( $context -> contextlevel == CONTEXT_MODULE ) {
$cm = get_coursemodule_from_id ( '' , $context -> instanceid , 0 , false , MUST_EXIST );
2013-08-21 13:42:30 +08:00
$course = $DB -> get_record ( 'course' , array ( 'id' => $cm -> course ), '*' , MUST_EXIST );
2007-10-05 15:06:38 +00:00
2011-10-14 12:48:00 +02:00
} else if ( $context -> contextlevel == CONTEXT_BLOCK ) {
$parent = $context -> get_parent_context ();
2008-09-06 13:17:15 +00:00
2011-10-14 12:48:00 +02:00
if ( $parent -> contextlevel == CONTEXT_COURSE ) {
2013-08-21 13:42:30 +08:00
$course = $DB -> get_record ( 'course' , array ( 'id' => $parent -> instanceid ), '*' , MUST_EXIST );
2011-10-14 12:48:00 +02:00
} else if ( $parent -> contextlevel == CONTEXT_MODULE ) {
$cm = get_coursemodule_from_id ( '' , $parent -> instanceid , 0 , false , MUST_EXIST );
2013-08-21 13:42:30 +08:00
$course = $DB -> get_record ( 'course' , array ( 'id' => $cm -> course ), '*' , MUST_EXIST );
2011-10-14 12:48:00 +02:00
}
2006-08-08 05:13:06 +00:00
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
return array ( $context , $course , $cm );
2006-08-08 05:13:06 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2011-10-14 12:48:00 +02:00
* Function that creates a role
2009-05-19 07:50:54 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param string $name role name
* @ param string $shortname role short name
* @ param string $description role description
* @ param string $archetype
* @ return int id or dml_exception
2007-01-30 10:10:25 +00:00
*/
2011-10-14 12:48:00 +02:00
function create_role ( $name , $shortname , $description , $archetype = '' ) {
global $DB ;
2007-10-05 15:06:38 +00:00
2011-10-14 12:48:00 +02:00
if ( strpos ( $archetype , 'moodle/legacy:' ) !== false ) {
throw new coding_exception ( 'Use new role archetype parameter in create_role() instead of old legacy capabilities.' );
2007-01-30 10:10:25 +00:00
}
2007-10-05 15:06:38 +00:00
2011-10-14 12:48:00 +02:00
// verify role archetype actually exists
$archetypes = get_role_archetypes ();
if ( empty ( $archetypes [ $archetype ])) {
$archetype = '' ;
2007-10-05 15:06:38 +00:00
}
2011-10-14 12:48:00 +02:00
// Insert the role record.
$role = new stdClass ();
$role -> name = $name ;
$role -> shortname = $shortname ;
$role -> description = $description ;
$role -> archetype = $archetype ;
//find free sortorder number
$role -> sortorder = $DB -> get_field ( 'role' , 'MAX(sortorder) + 1' , array ());
if ( empty ( $role -> sortorder )) {
$role -> sortorder = 1 ;
2007-10-05 15:06:38 +00:00
}
2011-10-14 12:48:00 +02:00
$id = $DB -> insert_record ( 'role' , $role );
2007-10-05 15:06:38 +00:00
2011-10-14 12:48:00 +02:00
return $id ;
2007-01-30 10:10:25 +00:00
}
2007-10-09 16:07:15 +00:00
2006-09-23 06:10:48 +00:00
/**
2011-10-14 12:48:00 +02:00
* Function that deletes a role and cleanups up after it
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid id of role to delete
* @ return bool always true
2006-09-23 06:10:48 +00:00
*/
2011-10-14 12:48:00 +02:00
function delete_role ( $roleid ) {
global $DB ;
2007-10-09 16:07:15 +00:00
2011-10-14 12:48:00 +02:00
// first unssign all users
role_unassign_all ( array ( 'roleid' => $roleid ));
2010-09-20 03:25:35 +00:00
2011-10-14 12:48:00 +02:00
// cleanup all references to this role, ignore errors
$DB -> delete_records ( 'role_capabilities' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_assign' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_assign' , array ( 'allowassign' => $roleid ));
$DB -> delete_records ( 'role_allow_override' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_override' , array ( 'allowoverride' => $roleid ));
$DB -> delete_records ( 'role_names' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_context_levels' , array ( 'roleid' => $roleid ));
2010-05-20 07:53:48 +00:00
2013-08-06 09:37:55 +08:00
// Get role record before it's deleted.
$role = $DB -> get_record ( 'role' , array ( 'id' => $roleid ));
2010-09-19 13:09:48 +00:00
2013-08-06 09:37:55 +08:00
// Finally delete the role itself.
2011-10-14 12:48:00 +02:00
$DB -> delete_records ( 'role' , array ( 'id' => $roleid ));
2010-09-19 13:09:48 +00:00
2013-08-06 09:37:55 +08:00
// Trigger event.
$event = \core\event\role_deleted :: create (
array (
'context' => context_system :: instance (),
'objectid' => $roleid ,
'other' =>
array (
'shortname' => $role -> shortname ,
'description' => $role -> description ,
'archetype' => $role -> archetype
)
)
);
$event -> add_record_snapshot ( 'role' , $role );
$event -> trigger ();
2010-05-20 07:40:17 +00:00
2016-05-14 21:14:31 +09:30
// Reset any cache of this role, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $roleid );
2016-05-14 21:14:31 +09:30
2010-05-20 07:40:17 +00:00
return true ;
2006-09-23 06:10:48 +00:00
}
2007-10-05 20:16:51 +00:00
/**
2011-10-14 12:48:00 +02:00
* Function to write context specific overrides , or default capabilities .
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param string $capability string name
* @ param int $permission CAP_ constants
* @ param int $roleid role id
* @ param int | context $contextid context id
* @ param bool $overwrite
* @ return bool always true or exception
2007-10-05 20:16:51 +00:00
*/
2011-10-14 12:48:00 +02:00
function assign_capability ( $capability , $permission , $roleid , $contextid , $overwrite = false ) {
global $USER , $DB ;
2007-10-05 20:16:51 +00:00
2011-10-14 12:48:00 +02:00
if ( $contextid instanceof context ) {
$context = $contextid ;
} else {
$context = context :: instance_by_id ( $contextid );
2007-10-05 20:16:51 +00:00
}
2019-02-28 08:39:20 +08:00
// Capability must exist.
if ( ! $capinfo = get_capability_info ( $capability )) {
throw new coding_exception ( " Capability ' { $capability } ' was not found! This has to be fixed in code. " );
}
2011-10-14 12:48:00 +02:00
if ( empty ( $permission ) || $permission == CAP_INHERIT ) { // if permission is not set
unassign_capability ( $capability , $roleid , $context -> id );
return true ;
2007-10-05 20:16:51 +00:00
}
2011-10-14 12:48:00 +02:00
$existing = $DB -> get_record ( 'role_capabilities' , array ( 'contextid' => $context -> id , 'roleid' => $roleid , 'capability' => $capability ));
2007-10-05 20:16:51 +00:00
2011-10-14 12:48:00 +02:00
if ( $existing and ! $overwrite ) { // We want to keep whatever is there already
return true ;
2007-10-05 20:16:51 +00:00
}
2011-10-14 12:48:00 +02:00
$cap = new stdClass ();
$cap -> contextid = $context -> id ;
$cap -> roleid = $roleid ;
$cap -> capability = $capability ;
$cap -> permission = $permission ;
$cap -> timemodified = time ();
$cap -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2009-07-13 08:37:34 +00:00
2011-10-14 12:48:00 +02:00
if ( $existing ) {
$cap -> id = $existing -> id ;
$DB -> update_record ( 'role_capabilities' , $cap );
} else {
if ( $DB -> record_exists ( 'context' , array ( 'id' => $context -> id ))) {
$DB -> insert_record ( 'role_capabilities' , $cap );
}
2007-10-05 20:16:51 +00:00
}
2016-05-14 21:14:31 +09:30
2019-07-17 19:59:01 +08:00
// Trigger capability_assigned event.
\core\event\capability_assigned :: create ([
'userid' => $cap -> modifierid ,
'context' => $context ,
'objectid' => $roleid ,
'other' => [
'capability' => $capability ,
'oldpermission' => $existing -> permission ? ? CAP_INHERIT ,
'permission' => $permission
]
]) -> trigger ();
2016-05-14 21:14:31 +09:30
// Reset any cache of this role, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $roleid );
2016-05-14 21:14:31 +09:30
2011-10-14 12:48:00 +02:00
return true ;
2007-10-05 20:16:51 +00:00
}
2007-09-19 06:50:53 +00:00
/**
2011-10-14 12:48:00 +02:00
* Unassign a capability from a role .
2007-09-19 06:50:53 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param string $capability the name of the capability
* @ param int $roleid the role id
* @ param int | context $contextid null means all contexts
* @ return boolean true or exception
2007-09-19 06:50:53 +00:00
*/
2011-10-14 12:48:00 +02:00
function unassign_capability ( $capability , $roleid , $contextid = null ) {
2019-07-17 20:24:00 +08:00
global $DB , $USER ;
2007-09-19 06:50:53 +00:00
2019-02-28 08:39:20 +08:00
// Capability must exist.
if ( ! $capinfo = get_capability_info ( $capability )) {
throw new coding_exception ( " Capability ' { $capability } ' was not found! This has to be fixed in code. " );
}
2011-10-14 12:48:00 +02:00
if ( ! empty ( $contextid )) {
if ( $contextid instanceof context ) {
$context = $contextid ;
} else {
$context = context :: instance_by_id ( $contextid );
}
// delete from context rel, if this is the last override in this context
$DB -> delete_records ( 'role_capabilities' , array ( 'capability' => $capability , 'roleid' => $roleid , 'contextid' => $context -> id ));
} else {
$DB -> delete_records ( 'role_capabilities' , array ( 'capability' => $capability , 'roleid' => $roleid ));
2007-09-19 06:50:53 +00:00
}
2016-05-14 21:14:31 +09:30
2019-07-17 20:24:00 +08:00
// Trigger capability_assigned event.
\core\event\capability_unassigned :: create ([
'userid' => $USER -> id ,
'context' => $context ? ? context_system :: instance (),
'objectid' => $roleid ,
'other' => [
'capability' => $capability ,
]
]) -> trigger ();
2016-05-14 21:14:31 +09:30
// Reset any cache of this role, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $roleid );
2016-05-14 21:14:31 +09:30
2007-09-19 06:50:53 +00:00
return true ;
}
2008-12-18 17:52:29 +00:00
/**
2011-10-14 12:48:00 +02:00
* Get the roles that have a given capability assigned to it
2008-12-18 17:52:29 +00:00
*
2011-10-14 12:48:00 +02:00
* This function does not resolve the actual permission of the capability .
* It just checks for permissions and overrides .
* Use get_roles_with_cap_in_context () if resolution is required .
*
2012-02-21 11:48:33 +13:00
* @ param string $capability capability name ( string )
* @ param string $permission optional , the permission defined for this capability
2011-10-14 12:48:00 +02:00
* either CAP_ALLOW , CAP_PREVENT or CAP_PROHIBIT . Defaults to null which means any .
2012-02-21 11:48:33 +13:00
* @ param stdClass $context null means any
2011-10-14 12:48:00 +02:00
* @ return array of role records
2008-12-18 17:52:29 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_roles_with_capability ( $capability , $permission = null , $context = null ) {
global $DB ;
2008-12-18 17:52:29 +00:00
2011-10-14 12:48:00 +02:00
if ( $context ) {
$contexts = $context -> get_parent_context_ids ( true );
list ( $insql , $params ) = $DB -> get_in_or_equal ( $contexts , SQL_PARAMS_NAMED , 'ctx' );
$contextsql = " AND rc.contextid $insql " ;
} else {
$params = array ();
$contextsql = '' ;
2008-12-18 17:52:29 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $permission ) {
$permissionsql = " AND rc.permission = :permission " ;
$params [ 'permission' ] = $permission ;
} else {
$permissionsql = '' ;
2008-12-18 17:52:29 +00:00
}
2011-10-14 12:48:00 +02:00
$sql = " SELECT r.*
FROM { role } r
WHERE r . id IN ( SELECT rc . roleid
FROM { role_capabilities } rc
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
WHERE rc . capability = : capname
$contextsql
$permissionsql ) " ;
$params [ 'capname' ] = $capability ;
return $DB -> get_records_sql ( $sql , $params );
2008-12-18 17:52:29 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* This function makes a role - assignment ( a role for a user in a particular context )
2009-05-19 07:50:54 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid the role of the id
* @ param int $userid userid
* @ param int | context $contextid id of the context
* @ param string $component example 'enrol_ldap' , defaults to '' which means manual assignment ,
* @ param int $itemid id of enrolment / auth plugin
* @ param string $timemodified defaults to current time
* @ return int new / existing id of the assignment
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_assign ( $roleid , $userid , $contextid , $component = '' , $itemid = 0 , $timemodified = '' ) {
2018-06-16 11:57:27 +08:00
global $USER , $DB ;
2006-08-23 01:29:52 +00:00
2011-10-14 12:48:00 +02:00
// first of all detect if somebody is using old style parameters
if ( $contextid === 0 or is_numeric ( $component )) {
throw new coding_exception ( 'Invalid call to role_assign(), code needs to be updated to use new order of parameters' );
2007-01-30 10:10:25 +00:00
}
2011-10-14 12:48:00 +02:00
// now validate all parameters
if ( empty ( $roleid )) {
throw new coding_exception ( 'Invalid call to role_assign(), roleid can not be empty' );
2006-09-27 17:58:17 +00:00
}
2011-10-14 12:48:00 +02:00
if ( empty ( $userid )) {
throw new coding_exception ( 'Invalid call to role_assign(), userid can not be empty' );
}
2010-10-26 16:21:23 +00:00
2011-10-14 12:48:00 +02:00
if ( $itemid ) {
if ( strpos ( $component , '_' ) === false ) {
throw new coding_exception ( 'Invalid call to role_assign(), component must start with plugin type such as"enrol_" when itemid specified' , 'component:' . $component );
2008-02-13 17:03:25 +00:00
}
2011-10-14 12:48:00 +02:00
} else {
$itemid = 0 ;
if ( $component !== '' and strpos ( $component , '_' ) === false ) {
throw new coding_exception ( 'Invalid call to role_assign(), invalid component string' , 'component:' . $component );
2008-02-13 17:03:25 +00:00
}
2011-10-14 12:48:00 +02:00
}
2008-02-13 17:03:25 +00:00
2011-10-14 12:48:00 +02:00
if ( ! $DB -> record_exists ( 'user' , array ( 'id' => $userid , 'deleted' => 0 ))) {
throw new coding_exception ( 'User ID does not exist or is deleted!' , 'userid:' . $userid );
}
2008-02-13 17:03:25 +00:00
2011-10-14 12:48:00 +02:00
if ( $contextid instanceof context ) {
$context = $contextid ;
} else {
$context = context :: instance_by_id ( $contextid , MUST_EXIST );
2006-08-13 13:28:01 +00:00
}
2011-10-14 12:48:00 +02:00
if ( ! $timemodified ) {
$timemodified = time ();
}
2008-02-13 17:03:25 +00:00
2011-12-20 22:36:31 +01:00
// Check for existing entry
2011-10-14 12:48:00 +02:00
$ras = $DB -> get_records ( 'role_assignments' , array ( 'roleid' => $roleid , 'contextid' => $context -> id , 'userid' => $userid , 'component' => $component , 'itemid' => $itemid ), 'id' );
2008-02-13 17:03:25 +00:00
2011-10-14 12:48:00 +02:00
if ( $ras ) {
// role already assigned - this should not happen
if ( count ( $ras ) > 1 ) {
// very weird - remove all duplicates!
$ra = array_shift ( $ras );
foreach ( $ras as $r ) {
$DB -> delete_records ( 'role_assignments' , array ( 'id' => $r -> id ));
}
} else {
$ra = reset ( $ras );
2008-02-13 17:03:25 +00:00
}
2006-08-13 13:28:01 +00:00
2011-10-14 12:48:00 +02:00
// actually there is no need to update, reset anything or trigger any event, so just return
return $ra -> id ;
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
// Create a new entry
$ra = new stdClass ();
$ra -> roleid = $roleid ;
$ra -> contextid = $context -> id ;
$ra -> userid = $userid ;
$ra -> component = $component ;
$ra -> itemid = $itemid ;
$ra -> timemodified = $timemodified ;
$ra -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2014-02-25 13:45:01 +08:00
$ra -> sortorder = 0 ;
2008-02-13 17:03:25 +00:00
2011-10-14 12:48:00 +02:00
$ra -> id = $DB -> insert_record ( 'role_assignments' , $ra );
2008-02-13 17:03:25 +00:00
2018-06-05 16:37:25 -04:00
// Role assignments have changed, so mark user as dirty.
mark_user_dirty ( $userid );
2006-08-14 05:55:40 +00:00
2018-06-16 11:57:27 +08:00
core_course_category :: role_assignment_changed ( $roleid , $context );
2015-08-14 12:28:09 +08:00
2014-04-23 17:41:12 -07:00
$event = \core\event\role_assigned :: create ( array (
'context' => $context ,
'objectid' => $ra -> roleid ,
'relateduserid' => $ra -> userid ,
'other' => array (
'id' => $ra -> id ,
'component' => $ra -> component ,
'itemid' => $ra -> itemid
)
));
2013-07-13 11:00:30 +02:00
$event -> add_record_snapshot ( 'role_assignments' , $ra );
2013-06-29 21:06:31 +02:00
$event -> trigger ();
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
return $ra -> id ;
}
2006-08-14 07:15:03 +00:00
2006-08-13 15:48:57 +00:00
/**
2011-10-14 12:48:00 +02:00
* Removes one role assignment
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid
* @ param int $userid
2013-06-18 14:04:44 +08:00
* @ param int $contextid
2011-10-14 12:48:00 +02:00
* @ param string $component
* @ param int $itemid
* @ return void
2006-08-13 15:48:57 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_unassign ( $roleid , $userid , $contextid , $component = '' , $itemid = 0 ) {
// first make sure the params make sense
if ( $roleid == 0 or $userid == 0 or $contextid == 0 ) {
throw new coding_exception ( 'Invalid call to role_unassign(), please use role_unassign_all() when removing multiple role assignments' );
2006-08-13 15:48:57 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $itemid ) {
if ( strpos ( $component , '_' ) === false ) {
throw new coding_exception ( 'Invalid call to role_assign(), component must start with plugin type such as "enrol_" when itemid specified' , 'component:' . $component );
}
} else {
$itemid = 0 ;
if ( $component !== '' and strpos ( $component , '_' ) === false ) {
throw new coding_exception ( 'Invalid call to role_assign(), invalid component string' , 'component:' . $component );
}
2006-08-13 15:48:57 +00:00
}
2011-10-14 12:48:00 +02:00
role_unassign_all ( array ( 'roleid' => $roleid , 'userid' => $userid , 'contextid' => $contextid , 'component' => $component , 'itemid' => $itemid ), false , false );
2006-08-13 15:48:57 +00:00
}
2006-08-13 09:25:45 +00:00
/**
2011-10-14 12:48:00 +02:00
* Removes multiple role assignments , parameters may contain :
* 'roleid' , 'userid' , 'contextid' , 'component' , 'enrolid' .
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param array $params role assignment parameters
* @ param bool $subcontexts unassign in subcontexts too
* @ param bool $includemanual include manual role assignments too
* @ return void
2010-03-07 09:28:54 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_unassign_all ( array $params , $subcontexts = false , $includemanual = false ) {
global $USER , $CFG , $DB ;
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
if ( ! $params ) {
throw new coding_exception ( 'Missing parameters in role_unsassign_all() call' );
}
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
$allowed = array ( 'roleid' , 'userid' , 'contextid' , 'component' , 'itemid' );
foreach ( $params as $key => $value ) {
if ( ! in_array ( $key , $allowed )) {
throw new coding_exception ( 'Unknown role_unsassign_all() parameter key' , 'key:' . $key );
2010-03-07 09:28:54 +00:00
}
}
2011-10-14 12:48:00 +02:00
if ( isset ( $params [ 'component' ]) and $params [ 'component' ] !== '' and strpos ( $params [ 'component' ], '_' ) === false ) {
throw new coding_exception ( 'Invalid component paramter in role_unsassign_all() call' , 'component:' . $params [ 'component' ]);
2011-02-13 18:59:53 +01:00
}
2011-10-14 12:48:00 +02:00
if ( $includemanual ) {
if ( ! isset ( $params [ 'component' ]) or $params [ 'component' ] === '' ) {
throw new coding_exception ( 'include manual parameter requires component parameter in role_unsassign_all() call' );
}
2010-07-30 20:51:01 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $subcontexts ) {
if ( empty ( $params [ 'contextid' ])) {
throw new coding_exception ( 'subcontexts paramtere requires component parameter in role_unsassign_all() call' );
}
2010-07-30 20:51:01 +00:00
}
2011-10-14 12:48:00 +02:00
$ras = $DB -> get_records ( 'role_assignments' , $params );
2020-05-06 09:14:49 +01:00
foreach ( $ras as $ra ) {
2011-10-14 12:48:00 +02:00
$DB -> delete_records ( 'role_assignments' , array ( 'id' => $ra -> id ));
if ( $context = context :: instance_by_id ( $ra -> contextid , IGNORE_MISSING )) {
2018-06-05 16:37:25 -04:00
// Role assignments have changed, so mark user as dirty.
mark_user_dirty ( $ra -> userid );
2014-04-23 17:41:12 -07:00
$event = \core\event\role_unassigned :: create ( array (
'context' => $context ,
'objectid' => $ra -> roleid ,
'relateduserid' => $ra -> userid ,
'other' => array (
'id' => $ra -> id ,
'component' => $ra -> component ,
'itemid' => $ra -> itemid
)
));
2013-07-13 11:00:30 +02:00
$event -> add_record_snapshot ( 'role_assignments' , $ra );
2013-06-29 21:06:31 +02:00
$event -> trigger ();
2018-06-16 11:57:27 +08:00
core_course_category :: role_assignment_changed ( $ra -> roleid , $context );
2011-10-14 12:48:00 +02:00
}
2010-07-30 20:51:01 +00:00
}
2011-10-14 12:48:00 +02:00
unset ( $ras );
// process subcontexts
if ( $subcontexts and $context = context :: instance_by_id ( $params [ 'contextid' ], IGNORE_MISSING )) {
if ( $params [ 'contextid' ] instanceof context ) {
$context = $params [ 'contextid' ];
} else {
$context = context :: instance_by_id ( $params [ 'contextid' ], IGNORE_MISSING );
}
2010-07-30 20:51:01 +00:00
2011-10-14 12:48:00 +02:00
if ( $context ) {
$contexts = $context -> get_child_contexts ();
$mparams = $params ;
2020-05-06 09:14:49 +01:00
foreach ( $contexts as $context ) {
2011-10-14 12:48:00 +02:00
$mparams [ 'contextid' ] = $context -> id ;
$ras = $DB -> get_records ( 'role_assignments' , $mparams );
2020-05-06 09:14:49 +01:00
foreach ( $ras as $ra ) {
2011-10-14 12:48:00 +02:00
$DB -> delete_records ( 'role_assignments' , array ( 'id' => $ra -> id ));
2018-06-05 16:37:25 -04:00
// Role assignments have changed, so mark user as dirty.
mark_user_dirty ( $ra -> userid );
2013-06-29 21:06:31 +02:00
$event = \core\event\role_unassigned :: create (
array ( 'context' => $context , 'objectid' => $ra -> roleid , 'relateduserid' => $ra -> userid ,
2013-07-09 15:00:15 +02:00
'other' => array ( 'id' => $ra -> id , 'component' => $ra -> component , 'itemid' => $ra -> itemid )));
2013-07-13 11:00:30 +02:00
$event -> add_record_snapshot ( 'role_assignments' , $ra );
2013-06-29 21:06:31 +02:00
$event -> trigger ();
2018-06-16 11:57:27 +08:00
core_course_category :: role_assignment_changed ( $ra -> roleid , $context );
2011-10-14 12:48:00 +02:00
}
}
}
2010-07-30 20:51:01 +00:00
}
2011-10-14 12:48:00 +02:00
// do this once more for all manual role assignments
if ( $includemanual ) {
$params [ 'component' ] = '' ;
role_unassign_all ( $params , $subcontexts , false );
}
2010-07-30 20:51:01 +00:00
}
2018-06-05 16:37:25 -04:00
/**
* Mark a user as dirty ( with timestamp ) so as to force reloading of the user session .
*
* @ param int $userid
* @ return void
*/
function mark_user_dirty ( $userid ) {
global $CFG , $ACCESSLIB_PRIVATE ;
if ( during_initial_install ()) {
return ;
}
// Throw exception if invalid userid is provided.
if ( empty ( $userid )) {
throw new coding_exception ( 'Invalid user parameter supplied for mark_user_dirty() function!' );
}
// Set dirty flag in database, set dirty field locally, and clear local accessdata cache.
set_cache_flag ( 'accesslib/dirtyusers' , $userid , 1 , time () + $CFG -> sessiontimeout );
$ACCESSLIB_PRIVATE -> dirtyusers [ $userid ] = 1 ;
unset ( $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ]);
}
2011-10-14 12:48:00 +02:00
/**
* Determines if a user is currently logged in
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2011-10-14 12:48:00 +02:00
* @ return bool
*/
function isloggedin () {
global $USER ;
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
return ( ! empty ( $USER -> id ));
}
2006-08-08 05:13:06 +00:00
2006-08-14 07:15:03 +00:00
/**
2011-10-14 12:48:00 +02:00
* Determines if a user is logged in as real guest user with username 'guest' .
2009-05-22 02:03:55 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2011-10-14 12:48:00 +02:00
* @ param int | object $user mixed user object or id , $USER if not specified
* @ return bool true if user is the real guest user , false if not logged in or other user
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function isguestuser ( $user = null ) {
global $USER , $DB , $CFG ;
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
// make sure we have the user id cached in config table, because we are going to use it a lot
if ( empty ( $CFG -> siteguest )) {
if ( ! $guestid = $DB -> get_field ( 'user' , 'id' , array ( 'username' => 'guest' , 'mnethostid' => $CFG -> mnet_localhost_id ))) {
// guest does not exist yet, weird
return false ;
}
set_config ( 'siteguest' , $guestid );
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $user === null ) {
$user = $USER ;
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $user === null ) {
// happens when setting the $USER
return false ;
2006-09-18 17:40:22 +00:00
2011-10-14 12:48:00 +02:00
} else if ( is_numeric ( $user )) {
return ( $CFG -> siteguest == $user );
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
} else if ( is_object ( $user )) {
if ( empty ( $user -> id )) {
return false ; // not logged in means is not be guest
} else {
return ( $CFG -> siteguest == $user -> id );
}
2006-09-21 22:34:45 +00:00
2011-10-14 12:48:00 +02:00
} else {
throw new coding_exception ( 'Invalid user parameter supplied for isguestuser() function!' );
}
2006-08-08 05:13:06 +00:00
}
2006-09-23 10:43:24 +00:00
/**
2011-10-14 12:48:00 +02:00
* Does user have a ( temporary or real ) guest access to course ?
2009-05-22 02:03:55 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2011-10-14 12:48:00 +02:00
* @ param context $context
* @ param stdClass | int $user
* @ return bool
2006-09-23 10:43:24 +00:00
*/
2011-10-14 12:48:00 +02:00
function is_guest ( context $context , $user = null ) {
global $USER ;
2007-09-13 13:44:35 +00:00
2011-10-14 12:48:00 +02:00
// first find the course context
$coursecontext = $context -> get_course_context ();
2007-09-13 13:44:35 +00:00
2011-10-14 12:48:00 +02:00
// make sure there is a real user specified
if ( $user === null ) {
$userid = isset ( $USER -> id ) ? $USER -> id : 0 ;
} else {
$userid = is_object ( $user ) ? $user -> id : $user ;
}
2007-07-19 05:19:05 +00:00
2011-10-14 12:48:00 +02:00
if ( isguestuser ( $userid )) {
// can not inspect or be enrolled
return true ;
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( has_capability ( 'moodle/course:view' , $coursecontext , $user )) {
// viewing users appear out of nowhere, they are neither guests nor participants
return false ;
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
// consider only real active enrolments here
if ( is_enrolled ( $coursecontext , $user , '' , true )) {
return false ;
}
2006-09-23 10:43:24 +00:00
2010-03-31 07:41:31 +00:00
return true ;
2006-09-23 10:43:24 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Returns true if the user has moodle / course : view capability in the course ,
* this is intended for admins , managers ( aka small admins ), inspectors , etc .
2009-05-19 07:50:54 +00:00
*
2012-01-14 19:12:43 +01:00
* @ category access
*
2011-10-14 12:48:00 +02:00
* @ param context $context
2012-02-21 11:48:33 +13:00
* @ param int | stdClass $user if null $USER is used
2011-10-14 12:48:00 +02:00
* @ param string $withcapability extra capability name
* @ return bool
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function is_viewing ( context $context , $user = null , $withcapability = '' ) {
// first find the course context
$coursecontext = $context -> get_course_context ();
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
if ( isguestuser ( $user )) {
// can not inspect
return false ;
2006-08-09 13:14:15 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
if ( ! has_capability ( 'moodle/course:view' , $coursecontext , $user )) {
// admins are allowed to inspect courses
return false ;
2006-09-12 06:15:33 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $withcapability and ! has_capability ( $withcapability , $context , $user )) {
// site admins always have the capability, but the enrolment above blocks
return false ;
2006-09-12 06:15:33 +00:00
}
2011-10-14 12:48:00 +02:00
2010-03-31 07:41:31 +00:00
return true ;
2006-08-08 05:13:06 +00:00
}
/**
2011-10-14 12:48:00 +02:00
* Returns true if the user is able to access the course .
2009-11-01 11:31:16 +00:00
*
2011-10-14 12:48:00 +02:00
* This function is in no way , shape , or form a substitute for require_login .
* It should only be used in circumstances where it is not possible to call require_login
* such as the navigation .
*
* This function checks many of the methods of access to a course such as the view
* capability , enrollments , and guest access . It also makes use of the cache
* generated by require_login for guest access .
*
* The flags within the $USER object that are used here should NEVER be used outside
* of this function can_access_course and require_login . Doing so WILL break future
* versions .
*
2011-10-29 09:45:54 +02:00
* @ param stdClass $course record
* @ param stdClass | int | null $user user record or id , current user if null
2011-10-14 12:48:00 +02:00
* @ param string $withcapability Check for this capability as well .
* @ param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
* @ return boolean Returns true if the user is able to access the course
*/
2011-10-29 09:45:54 +02:00
function can_access_course ( stdClass $course , $user = null , $withcapability = '' , $onlyactive = false ) {
2011-10-14 12:48:00 +02:00
global $DB , $USER ;
2006-09-20 21:00:45 +00:00
2011-10-29 09:45:54 +02:00
// this function originally accepted $coursecontext parameter
if ( $course instanceof context ) {
if ( $course instanceof context_course ) {
debugging ( 'deprecated context parameter, please use $course record' );
$coursecontext = $course ;
$course = $DB -> get_record ( 'course' , array ( 'id' => $coursecontext -> instanceid ));
} else {
debugging ( 'Invalid context parameter, please use $course record' );
return false ;
}
} else {
$coursecontext = context_course :: instance ( $course -> id );
}
if ( ! isset ( $USER -> id )) {
// should never happen
$USER -> id = 0 ;
2012-10-26 10:43:39 +08:00
debugging ( 'Course access check being performed on a user with no ID.' , DEBUG_DEVELOPER );
2011-10-29 09:45:54 +02:00
}
// make sure there is a user specified
if ( $user === null ) {
$userid = $USER -> id ;
} else {
$userid = is_object ( $user ) ? $user -> id : $user ;
}
unset ( $user );
2006-08-08 05:13:06 +00:00
2011-10-29 09:45:54 +02:00
if ( $withcapability and ! has_capability ( $withcapability , $coursecontext , $userid )) {
return false ;
}
if ( $userid == $USER -> id ) {
if ( ! empty ( $USER -> access [ 'rsw' ][ $coursecontext -> path ])) {
// the fact that somebody switched role means they can access the course no matter to what role they switched
return true ;
}
}
2011-10-30 10:53:42 +01:00
if ( ! $course -> visible and ! has_capability ( 'moodle/course:viewhiddencourses' , $coursecontext , $userid )) {
2011-10-29 09:45:54 +02:00
return false ;
}
if ( is_viewing ( $coursecontext , $userid )) {
2011-10-14 12:48:00 +02:00
return true ;
2006-08-08 05:13:06 +00:00
}
2011-10-29 09:45:54 +02:00
if ( $userid != $USER -> id ) {
// for performance reasons we do not verify temporary guest access for other users, sorry...
return is_enrolled ( $coursecontext , $userid , '' , $onlyactive );
}
2011-10-30 10:53:42 +01:00
// === from here we deal only with $USER ===
2011-11-05 12:12:48 +01:00
$coursecontext -> reload_if_dirty ();
2011-10-29 09:45:54 +02:00
if ( isset ( $USER -> enrol [ 'enrolled' ][ $course -> id ])) {
2011-11-05 12:12:48 +01:00
if ( $USER -> enrol [ 'enrolled' ][ $course -> id ] > time ()) {
2011-10-29 09:45:54 +02:00
return true ;
}
}
if ( isset ( $USER -> enrol [ 'tempguest' ][ $course -> id ])) {
2011-11-05 12:12:48 +01:00
if ( $USER -> enrol [ 'tempguest' ][ $course -> id ] > time ()) {
2011-10-29 09:45:54 +02:00
return true ;
}
}
2006-09-03 07:56:40 +00:00
2011-11-05 12:12:48 +01:00
if ( is_enrolled ( $coursecontext , $USER , '' , $onlyactive )) {
2011-10-29 09:45:54 +02:00
return true ;
2008-07-06 19:30:12 +00:00
}
2007-09-13 13:44:35 +00:00
2018-06-21 13:34:59 +08:00
if ( ! core_course_category :: can_view_course_info ( $course )) {
// No guest access if user does not have capability to browse courses.
return false ;
}
2011-10-29 09:45:54 +02:00
// if not enrolled try to gain temporary guest access
$instances = $DB -> get_records ( 'enrol' , array ( 'courseid' => $course -> id , 'status' => ENROL_INSTANCE_ENABLED ), 'sortorder, id ASC' );
$enrols = enrol_get_plugins ( true );
2020-05-06 09:14:49 +01:00
foreach ( $instances as $instance ) {
2011-10-29 09:45:54 +02:00
if ( ! isset ( $enrols [ $instance -> enrol ])) {
continue ;
}
2011-11-05 12:12:48 +01:00
// Get a duration for the guest access, a timestamp in the future, 0 (always) or false.
2011-10-29 09:45:54 +02:00
$until = $enrols [ $instance -> enrol ] -> try_guestaccess ( $instance );
2011-11-05 12:12:48 +01:00
if ( $until !== false and $until > time ()) {
2011-10-29 09:45:54 +02:00
$USER -> enrol [ 'tempguest' ][ $course -> id ] = $until ;
return true ;
2011-10-14 12:48:00 +02:00
}
2006-09-17 08:42:42 +00:00
}
2011-11-05 12:12:48 +01:00
if ( isset ( $USER -> enrol [ 'tempguest' ][ $course -> id ])) {
unset ( $USER -> enrol [ 'tempguest' ][ $course -> id ]);
remove_temp_course_roles ( $coursecontext );
}
2011-10-29 09:45:54 +02:00
return false ;
2006-08-08 05:13:06 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Loads the capability definitions for the component ( from file ) .
*
* Loads the capability definitions for the component ( from file ) . If no
* capabilities are defined for the component , we simply return an empty array .
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ param string $component full plugin name , examples : 'moodle' , 'mod_forum'
* @ return array array of capabilities
*/
function load_capability_def ( $component ) {
2013-07-16 22:42:37 +02:00
$defpath = core_component :: get_component_directory ( $component ) . '/db/access.php' ;
2011-10-14 12:48:00 +02:00
$capabilities = array ();
if ( file_exists ( $defpath )) {
require ( $defpath );
if ( ! empty ( $ { $component . '_capabilities' })) {
// BC capability array name
// since 2.0 we prefer $capabilities instead - it is easier to use and matches db/* files
2011-10-25 14:20:22 +02:00
debugging ( 'componentname_capabilities array is deprecated, please use $capabilities array only in access.php files' );
2011-10-14 12:48:00 +02:00
$capabilities = $ { $component . '_capabilities' };
}
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
return $capabilities ;
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Gets the capabilities that have been cached in the database for this component .
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ param string $component - examples : 'moodle' , 'mod_forum'
* @ return array array of capabilities
*/
function get_cached_capabilities ( $component = 'moodle' ) {
global $DB ;
2015-03-17 12:43:30 +10:30
$caps = get_all_capabilities ();
$componentcaps = array ();
foreach ( $caps as $cap ) {
if ( $cap [ 'component' ] == $component ) {
$componentcaps [] = ( object ) $cap ;
}
}
return $componentcaps ;
2011-10-14 12:48:00 +02:00
}
2010-03-31 07:41:31 +00:00
/**
2011-10-14 12:48:00 +02:00
* Returns default capabilities for given role archetype .
2010-03-31 07:41:31 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param string $archetype role archetype
* @ return array
2010-03-31 07:41:31 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_default_capabilities ( $archetype ) {
global $DB ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
if ( ! $archetype ) {
return array ();
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
$alldefs = array ();
$defaults = array ();
$components = array ();
2015-03-17 12:43:30 +10:30
$allcaps = get_all_capabilities ();
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
foreach ( $allcaps as $cap ) {
2015-03-17 12:43:30 +10:30
if ( ! in_array ( $cap [ 'component' ], $components )) {
$components [] = $cap [ 'component' ];
$alldefs = array_merge ( $alldefs , load_capability_def ( $cap [ 'component' ]));
2011-10-14 12:48:00 +02:00
}
}
2020-05-06 09:14:49 +01:00
foreach ( $alldefs as $name => $def ) {
2011-10-14 12:48:00 +02:00
// Use array 'archetypes if available. Only if not specified, use 'legacy'.
if ( isset ( $def [ 'archetypes' ])) {
if ( isset ( $def [ 'archetypes' ][ $archetype ])) {
$defaults [ $name ] = $def [ 'archetypes' ][ $archetype ];
}
// 'legacy' is for backward compatibility with 1.9 access.php
} else {
if ( isset ( $def [ 'legacy' ][ $archetype ])) {
$defaults [ $name ] = $def [ 'legacy' ][ $archetype ];
}
}
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
return $defaults ;
2010-03-31 07:41:31 +00:00
}
2013-06-17 11:27:42 +02:00
/**
* Return default roles that can be assigned , overridden or switched
* by give role archetype .
*
2017-11-15 15:08:10 +00:00
* @ param string $type assign | override | switch | view
2013-06-17 11:27:42 +02:00
* @ param string $archetype
* @ return array of role ids
*/
function get_default_role_archetype_allows ( $type , $archetype ) {
global $DB ;
if ( empty ( $archetype )) {
return array ();
}
$roles = $DB -> get_records ( 'role' );
$archetypemap = array ();
foreach ( $roles as $role ) {
if ( $role -> archetype ) {
$archetypemap [ $role -> archetype ][ $role -> id ] = $role -> id ;
}
}
$defaults = array (
'assign' => array (
'manager' => array ( 'manager' , 'coursecreator' , 'editingteacher' , 'teacher' , 'student' ),
'coursecreator' => array (),
'editingteacher' => array ( 'teacher' , 'student' ),
'teacher' => array (),
'student' => array (),
'guest' => array (),
'user' => array (),
'frontpage' => array (),
),
'override' => array (
'manager' => array ( 'manager' , 'coursecreator' , 'editingteacher' , 'teacher' , 'student' , 'guest' , 'user' , 'frontpage' ),
'coursecreator' => array (),
'editingteacher' => array ( 'teacher' , 'student' , 'guest' ),
'teacher' => array (),
'student' => array (),
'guest' => array (),
'user' => array (),
'frontpage' => array (),
),
'switch' => array (
'manager' => array ( 'editingteacher' , 'teacher' , 'student' , 'guest' ),
'coursecreator' => array (),
'editingteacher' => array ( 'teacher' , 'student' , 'guest' ),
'teacher' => array ( 'student' , 'guest' ),
'student' => array (),
'guest' => array (),
'user' => array (),
'frontpage' => array (),
),
2017-11-15 15:08:10 +00:00
'view' => array (
'manager' => array ( 'manager' , 'coursecreator' , 'editingteacher' , 'teacher' , 'student' , 'guest' , 'user' , 'frontpage' ),
'coursecreator' => array ( 'coursecreator' , 'editingteacher' , 'teacher' , 'student' ),
'editingteacher' => array ( 'coursecreator' , 'editingteacher' , 'teacher' , 'student' ),
'teacher' => array ( 'coursecreator' , 'editingteacher' , 'teacher' , 'student' ),
'student' => array ( 'coursecreator' , 'editingteacher' , 'teacher' , 'student' ),
'guest' => array (),
'user' => array (),
'frontpage' => array (),
),
2013-06-17 11:27:42 +02:00
);
if ( ! isset ( $defaults [ $type ][ $archetype ])) {
debugging ( " Unknown type ' $type '' or archetype ' $archetype '' " );
return array ();
}
$return = array ();
foreach ( $defaults [ $type ][ $archetype ] as $at ) {
if ( isset ( $archetypemap [ $at ])) {
foreach ( $archetypemap [ $at ] as $roleid ) {
$return [ $roleid ] = $roleid ;
}
}
}
return $return ;
}
2010-03-31 07:41:31 +00:00
/**
2011-10-14 12:48:00 +02:00
* Reset role capabilities to default according to selected role archetype .
* If no archetype selected , removes all capabilities .
2010-03-31 07:41:31 +00:00
*
2014-01-14 13:44:17 +00:00
* This applies to capabilities that are assigned to the role ( that you could
* edit in the 'define roles' interface ), and not to any capability overrides
* in different locations .
*
* @ param int $roleid ID of role to reset capabilities for
2010-03-31 07:41:31 +00:00
*/
2011-10-14 12:48:00 +02:00
function reset_role_capabilities ( $roleid ) {
global $DB ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
$role = $DB -> get_record ( 'role' , array ( 'id' => $roleid ), '*' , MUST_EXIST );
$defaultcaps = get_default_capabilities ( $role -> archetype );
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
$systemcontext = context_system :: instance ();
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2014-01-08 17:11:10 +00:00
$DB -> delete_records ( 'role_capabilities' ,
2014-01-14 13:44:17 +00:00
array ( 'roleid' => $roleid , 'contextid' => $systemcontext -> id ));
2010-03-31 07:41:31 +00:00
2020-05-06 09:14:49 +01:00
foreach ( $defaultcaps as $cap => $permission ) {
2011-10-14 12:48:00 +02:00
assign_capability ( $cap , $permission , $roleid , $systemcontext -> id );
2010-03-31 07:41:31 +00:00
}
2014-01-14 13:44:17 +00:00
2016-05-14 21:14:31 +09:30
// Reset any cache of this role, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $roleid );
2010-03-31 07:41:31 +00:00
}
2010-11-11 03:37:56 +00:00
/**
2011-10-14 12:48:00 +02:00
* Updates the capabilities table with the component capability definitions .
* If no parameters are given , the function updates the core moodle
* capabilities .
2010-11-11 03:37:56 +00:00
*
2011-10-14 12:48:00 +02:00
* Note that the absence of the db / access . php capabilities definition file
* will cause any stored capabilities for the component to be removed from
* the database .
2010-11-11 03:37:56 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2021-09-30 07:42:14 +02:00
* @ param string $component examples : 'moodle' , 'mod_forum' , 'block_activity_results'
2011-10-14 12:48:00 +02:00
* @ return boolean true if success , exception in case of any problems
2010-11-11 03:37:56 +00:00
*/
2011-10-14 12:48:00 +02:00
function update_capabilities ( $component = 'moodle' ) {
global $DB , $OUTPUT ;
2010-11-11 03:37:56 +00:00
2011-10-14 12:48:00 +02:00
$storedcaps = array ();
2010-11-11 03:37:56 +00:00
2011-10-14 12:48:00 +02:00
$filecaps = load_capability_def ( $component );
2020-05-06 09:14:49 +01:00
foreach ( $filecaps as $capname => $unused ) {
2011-10-14 12:48:00 +02:00
if ( ! preg_match ( '|^[a-z]+/[a-z_0-9]+:[a-z_0-9]+$|' , $capname )) {
debugging ( " Coding problem: Invalid capability name ' $capname ', use 'clonepermissionsfrom' field for migration. " );
}
2010-11-11 03:37:56 +00:00
}
2015-03-17 12:43:30 +10:30
// It is possible somebody directly modified the DB (according to accesslib_test anyway).
// So ensure our updating is based on fresh data.
cache :: make ( 'core' , 'capabilities' ) -> delete ( 'core_capabilities' );
2011-10-14 12:48:00 +02:00
$cachedcaps = get_cached_capabilities ( $component );
if ( $cachedcaps ) {
foreach ( $cachedcaps as $cachedcap ) {
array_push ( $storedcaps , $cachedcap -> name );
// update risk bitmasks and context levels in existing capabilities if needed
if ( array_key_exists ( $cachedcap -> name , $filecaps )) {
if ( ! array_key_exists ( 'riskbitmask' , $filecaps [ $cachedcap -> name ])) {
$filecaps [ $cachedcap -> name ][ 'riskbitmask' ] = 0 ; // no risk if not specified
}
if ( $cachedcap -> captype != $filecaps [ $cachedcap -> name ][ 'captype' ]) {
$updatecap = new stdClass ();
$updatecap -> id = $cachedcap -> id ;
$updatecap -> captype = $filecaps [ $cachedcap -> name ][ 'captype' ];
$DB -> update_record ( 'capabilities' , $updatecap );
}
if ( $cachedcap -> riskbitmask != $filecaps [ $cachedcap -> name ][ 'riskbitmask' ]) {
$updatecap = new stdClass ();
$updatecap -> id = $cachedcap -> id ;
$updatecap -> riskbitmask = $filecaps [ $cachedcap -> name ][ 'riskbitmask' ];
$DB -> update_record ( 'capabilities' , $updatecap );
}
2010-11-11 03:37:56 +00:00
2011-10-14 12:48:00 +02:00
if ( ! array_key_exists ( 'contextlevel' , $filecaps [ $cachedcap -> name ])) {
$filecaps [ $cachedcap -> name ][ 'contextlevel' ] = 0 ; // no context level defined
}
if ( $cachedcap -> contextlevel != $filecaps [ $cachedcap -> name ][ 'contextlevel' ]) {
$updatecap = new stdClass ();
$updatecap -> id = $cachedcap -> id ;
$updatecap -> contextlevel = $filecaps [ $cachedcap -> name ][ 'contextlevel' ];
$DB -> update_record ( 'capabilities' , $updatecap );
}
2010-11-11 03:37:56 +00:00
}
2011-10-14 12:48:00 +02:00
}
}
2015-03-17 12:43:30 +10:30
// Flush the cached again, as we have changed DB.
cache :: make ( 'core' , 'capabilities' ) -> delete ( 'core_capabilities' );
2011-10-14 12:48:00 +02:00
// Are there new capabilities in the file definition?
$newcaps = array ();
foreach ( $filecaps as $filecap => $def ) {
if ( ! $storedcaps ||
( $storedcaps && in_array ( $filecap , $storedcaps ) === false )) {
if ( ! array_key_exists ( 'riskbitmask' , $def )) {
$def [ 'riskbitmask' ] = 0 ; // no risk if not specified
2010-11-11 03:37:56 +00:00
}
2011-10-14 12:48:00 +02:00
$newcaps [ $filecap ] = $def ;
2010-11-11 03:37:56 +00:00
}
}
2011-10-14 12:48:00 +02:00
// Add new capabilities to the stored definition.
2012-04-19 08:47:06 +02:00
$existingcaps = $DB -> get_records_menu ( 'capabilities' , array (), 'id' , 'id, name' );
2011-10-14 12:48:00 +02:00
foreach ( $newcaps as $capname => $capdef ) {
$capability = new stdClass ();
$capability -> name = $capname ;
$capability -> captype = $capdef [ 'captype' ];
$capability -> contextlevel = $capdef [ 'contextlevel' ];
$capability -> component = $component ;
$capability -> riskbitmask = $capdef [ 'riskbitmask' ];
2010-11-11 03:37:56 +00:00
2011-10-14 12:48:00 +02:00
$DB -> insert_record ( 'capabilities' , $capability , false );
2019-02-28 08:39:20 +08:00
// Flush the cached, as we have changed DB.
cache :: make ( 'core' , 'capabilities' ) -> delete ( 'core_capabilities' );
2012-04-19 08:47:06 +02:00
if ( isset ( $capdef [ 'clonepermissionsfrom' ]) && in_array ( $capdef [ 'clonepermissionsfrom' ], $existingcaps )){
2011-10-14 12:48:00 +02:00
if ( $rolecapabilities = $DB -> get_records ( 'role_capabilities' , array ( 'capability' => $capdef [ 'clonepermissionsfrom' ]))){
foreach ( $rolecapabilities as $rolecapability ){
//assign_capability will update rather than insert if capability exists
if ( ! assign_capability ( $capname , $rolecapability -> permission ,
$rolecapability -> roleid , $rolecapability -> contextid , true )){
echo $OUTPUT -> notification ( 'Could not clone capabilities for ' . $capname );
}
}
}
// we ignore archetype key if we have cloned permissions
} else if ( isset ( $capdef [ 'archetypes' ]) && is_array ( $capdef [ 'archetypes' ])) {
assign_legacy_capabilities ( $capname , $capdef [ 'archetypes' ]);
// 'legacy' is for backward compatibility with 1.9 access.php
} else if ( isset ( $capdef [ 'legacy' ]) && is_array ( $capdef [ 'legacy' ])) {
assign_legacy_capabilities ( $capname , $capdef [ 'legacy' ]);
2010-11-11 03:37:56 +00:00
}
}
2011-10-14 12:48:00 +02:00
// Are there any capabilities that have been removed from the file
// definition that we need to delete from the stored capabilities and
// role assignments?
capabilities_cleanup ( $component , $filecaps );
// reset static caches
2018-06-05 15:13:02 -04:00
accesslib_reset_role_cache ();
2011-10-14 12:48:00 +02:00
2015-03-17 12:43:30 +10:30
// Flush the cached again, as we have changed DB.
cache :: make ( 'core' , 'capabilities' ) -> delete ( 'core_capabilities' );
2011-10-14 12:48:00 +02:00
return true ;
2010-11-11 03:37:56 +00:00
}
2010-03-31 07:41:31 +00:00
/**
2011-10-14 12:48:00 +02:00
* Deletes cached capabilities that are no longer needed by the component .
* Also unassigns these capabilities from any roles that have them .
2013-07-15 13:56:39 +08:00
* NOTE : this function is called from lib / db / upgrade . php
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
*
2012-01-14 19:12:43 +01:00
* @ access private
2021-09-30 07:42:14 +02:00
* @ param string $component examples : 'moodle' , 'mod_forum' , 'block_activity_results'
2011-10-14 12:48:00 +02:00
* @ param array $newcapdef array of the new capability definitions that will be
* compared with the cached capabilities
* @ return int number of deprecated capabilities that have been removed
2010-03-31 07:41:31 +00:00
*/
2011-10-14 12:48:00 +02:00
function capabilities_cleanup ( $component , $newcapdef = null ) {
global $DB ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
$removedcount = 0 ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
if ( $cachedcaps = get_cached_capabilities ( $component )) {
foreach ( $cachedcaps as $cachedcap ) {
if ( empty ( $newcapdef ) ||
array_key_exists ( $cachedcap -> name , $newcapdef ) === false ) {
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
// Delete from roles.
if ( $roles = get_roles_with_capability ( $cachedcap -> name )) {
2020-05-06 09:14:49 +01:00
foreach ( $roles as $role ) {
2011-10-14 12:48:00 +02:00
if ( ! unassign_capability ( $cachedcap -> name , $role -> id )) {
2022-04-12 09:38:41 +05:30
throw new \moodle_exception ( 'cannotunassigncap' , 'error' , '' ,
( object ) array ( 'cap' => $cachedcap -> name , 'role' => $role -> name ));
2011-10-14 12:48:00 +02:00
}
}
}
2019-02-28 08:39:20 +08:00
// Remove from role_capabilities for any old ones.
$DB -> delete_records ( 'role_capabilities' , array ( 'capability' => $cachedcap -> name ));
// Remove from capabilities cache.
$DB -> delete_records ( 'capabilities' , array ( 'name' => $cachedcap -> name ));
$removedcount ++ ;
2011-10-14 12:48:00 +02:00
} // End if.
}
}
2015-03-17 12:43:30 +10:30
if ( $removedcount ) {
cache :: make ( 'core' , 'capabilities' ) -> delete ( 'core_capabilities' );
}
2011-10-14 12:48:00 +02:00
return $removedcount ;
}
/**
* Returns an array of all the known types of risk
* The array keys can be used , for example as CSS class names , or in calls to
* print_risk_icon . The values are the corresponding RISK_ constants .
*
* @ return array all the known types of risk .
*/
function get_all_risks () {
return array (
'riskmanagetrust' => RISK_MANAGETRUST ,
'riskconfig' => RISK_CONFIG ,
'riskxss' => RISK_XSS ,
'riskpersonal' => RISK_PERSONAL ,
'riskspam' => RISK_SPAM ,
'riskdataloss' => RISK_DATALOSS ,
);
}
/**
* Return a link to moodle docs for a given capability name
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $capability a capability - a row from the mdl_capabilities table .
2011-10-14 12:48:00 +02:00
* @ return string the human - readable capability name as a link to Moodle Docs .
*/
function get_capability_docs_link ( $capability ) {
$url = get_docs_url ( 'Capabilities/' . $capability -> name );
return '<a onclick="this.target=\'docspopup\'" href="' . $url . '">' . get_capability_string ( $capability -> name ) . '</a>' ;
}
/**
* This function pulls out all the resolved capabilities ( overrides and
* defaults ) of a role used in capability overrides in contexts at a given
* context .
*
* @ param int $roleid
2012-02-21 11:48:33 +13:00
* @ param context $context
2011-10-14 12:48:00 +02:00
* @ param string $cap capability , optional , defaults to ''
2012-02-21 11:48:33 +13:00
* @ return array Array of capabilities
2011-10-14 12:48:00 +02:00
*/
function role_context_capabilities ( $roleid , context $context , $cap = '' ) {
global $DB ;
$contexts = $context -> get_parent_context_ids ( true );
$contexts = '(' . implode ( ',' , $contexts ) . ')' ;
$params = array ( $roleid );
if ( $cap ) {
$search = " AND rc.capability = ? " ;
$params [] = $cap ;
} else {
$search = '' ;
}
$sql = " SELECT rc.*
2019-02-28 08:39:20 +08:00
FROM { role_capabilities } rc
JOIN { context } c ON rc . contextid = c . id
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
WHERE rc . contextid in $contexts
AND rc . roleid = ?
2019-02-28 08:39:20 +08:00
$search
2011-10-14 12:48:00 +02:00
ORDER BY c . contextlevel DESC , rc . capability DESC " ;
$capabilities = array ();
if ( $records = $DB -> get_records_sql ( $sql , $params )) {
// We are traversing via reverse order.
foreach ( $records as $record ) {
// If not set yet (i.e. inherit or not set at all), or currently we have a prohibit
if ( ! isset ( $capabilities [ $record -> capability ]) || $record -> permission <- 500 ) {
$capabilities [ $record -> capability ] = $record -> permission ;
}
}
}
return $capabilities ;
}
/**
* Constructs array with contextids as first parameter and context paths ,
* in both cases bottom top including self .
*
2012-01-14 19:12:43 +01:00
* @ access private
2011-10-14 12:48:00 +02:00
* @ param context $context
* @ return array
*/
function get_context_info_list ( context $context ) {
$contextids = explode ( '/' , ltrim ( $context -> path , '/' ));
$contextpaths = array ();
$contextids2 = $contextids ;
while ( $contextids2 ) {
$contextpaths [] = '/' . implode ( '/' , $contextids2 );
array_pop ( $contextids2 );
}
return array ( $contextids , $contextpaths );
}
/**
* Check if context is the front page context or a context inside it
*
* Returns true if this context is the front page context , or a context inside it ,
* otherwise false .
*
* @ param context $context a context object .
* @ return bool
*/
function is_inside_frontpage ( context $context ) {
$frontpagecontext = context_course :: instance ( SITEID );
return strpos ( $context -> path . '/' , $frontpagecontext -> path . '/' ) === 0 ;
}
/**
* Returns capability information ( cached )
*
* @ param string $capabilityname
2012-01-14 19:12:43 +01:00
* @ return stdClass or null if capability not found
2011-10-14 12:48:00 +02:00
*/
function get_capability_info ( $capabilityname ) {
2015-03-17 12:43:30 +10:30
$caps = get_all_capabilities ();
2011-10-14 12:48:00 +02:00
2022-04-22 14:27:44 +02:00
// Check for deprecated capability.
if ( $deprecatedinfo = get_deprecated_capability_info ( $capabilityname )) {
if ( ! empty ( $deprecatedinfo [ 'replacement' ])) {
// Let's try again with this capability if it exists.
if ( isset ( $caps [ $deprecatedinfo [ 'replacement' ]])) {
$capabilityname = $deprecatedinfo [ 'replacement' ];
} else {
debugging ( " Capability ' { $capabilityname } ' was supposed to be replaced with " .
" ' { $deprecatedinfo [ 'replacement' ] } ', which does not exist ! " );
}
}
$fullmessage = $deprecatedinfo [ 'fullmessage' ];
debugging ( $fullmessage , DEBUG_DEVELOPER );
}
2015-03-17 12:43:30 +10:30
if ( ! isset ( $caps [ $capabilityname ])) {
return null ;
2011-10-14 12:48:00 +02:00
}
2015-03-17 12:43:30 +10:30
return ( object ) $caps [ $capabilityname ];
}
2022-04-22 14:27:44 +02:00
/**
* Returns deprecation info for this particular capabilty ( cached )
*
* Do not use this function except in the get_capability_info
*
* @ param string $capabilityname
* @ return stdClass | null with deprecation message and potential replacement if not null
*/
function get_deprecated_capability_info ( $capabilityname ) {
2023-06-07 11:59:24 +02:00
$cache = cache :: make ( 'core' , 'capabilities' );
$alldeprecatedcaps = $cache -> get ( 'deprecated_capabilities' );
if ( $alldeprecatedcaps === false ) {
// Look for deprecated capabilities in each component.
2022-04-22 14:27:44 +02:00
$allcaps = get_all_capabilities ();
$components = [];
$alldeprecatedcaps = [];
foreach ( $allcaps as $cap ) {
if ( ! in_array ( $cap [ 'component' ], $components )) {
$components [] = $cap [ 'component' ];
$defpath = core_component :: get_component_directory ( $cap [ 'component' ]) . '/db/access.php' ;
if ( file_exists ( $defpath )) {
$deprecatedcapabilities = [];
require ( $defpath );
if ( ! empty ( $deprecatedcapabilities )) {
foreach ( $deprecatedcapabilities as $cname => $cdef ) {
2023-06-07 11:59:24 +02:00
$alldeprecatedcaps [ $cname ] = $cdef ;
2022-04-22 14:27:44 +02:00
}
}
}
}
}
2023-06-07 11:59:24 +02:00
$cache -> set ( 'deprecated_capabilities' , $alldeprecatedcaps );
2022-04-22 14:27:44 +02:00
}
2023-06-07 11:59:24 +02:00
if ( ! isset ( $alldeprecatedcaps [ $capabilityname ])) {
2022-04-22 14:27:44 +02:00
return null ;
}
2023-06-07 11:59:24 +02:00
$deprecatedinfo = $alldeprecatedcaps [ $capabilityname ];
2022-04-22 14:27:44 +02:00
$deprecatedinfo [ 'fullmessage' ] = " The capability ' { $capabilityname } ' is deprecated. " ;
if ( ! empty ( $deprecatedinfo [ 'message' ])) {
$deprecatedinfo [ 'fullmessage' ] .= $deprecatedinfo [ 'message' ];
}
if ( ! empty ( $deprecatedinfo [ 'replacement' ])) {
$deprecatedinfo [ 'fullmessage' ] .=
" It will be replaced by ' { $deprecatedinfo [ 'replacement' ] } '. " ;
}
return $deprecatedinfo ;
}
2015-03-17 12:43:30 +10:30
/**
* Returns all capabilitiy records , preferably from MUC and not database .
*
2015-06-16 09:03:28 +01:00
* @ return array All capability records indexed by capability name
2015-03-17 12:43:30 +10:30
*/
function get_all_capabilities () {
global $DB ;
$cache = cache :: make ( 'core' , 'capabilities' );
if ( ! $allcaps = $cache -> get ( 'core_capabilities' )) {
2015-06-16 09:03:28 +01:00
$rs = $DB -> get_recordset ( 'capabilities' );
$allcaps = array ();
foreach ( $rs as $capability ) {
$capability -> riskbitmask = ( int ) $capability -> riskbitmask ;
$allcaps [ $capability -> name ] = ( array ) $capability ;
2015-03-17 12:43:30 +10:30
}
2015-06-16 09:03:28 +01:00
$rs -> close ();
2015-03-17 12:43:30 +10:30
$cache -> set ( 'core_capabilities' , $allcaps );
}
return $allcaps ;
2011-10-14 12:48:00 +02:00
}
/**
* Returns the human - readable , translated version of the capability .
* Basically a big switch statement .
*
* @ param string $capabilityname e . g . mod / choice : readresponses
* @ return string
*/
function get_capability_string ( $capabilityname ) {
// Typical capability name is 'plugintype/pluginname:capabilityname'
list ( $type , $name , $capname ) = preg_split ( '|[/:]|' , $capabilityname );
if ( $type === 'moodle' ) {
$component = 'core_role' ;
} else if ( $type === 'quizreport' ) {
//ugly hack!!
$component = 'quiz_' . $name ;
} else {
$component = $type . '_' . $name ;
}
$stringname = $name . ':' . $capname ;
if ( $component === 'core_role' or get_string_manager () -> string_exists ( $stringname , $component )) {
return get_string ( $stringname , $component );
}
2013-07-16 22:42:37 +02:00
$dir = core_component :: get_component_directory ( $component );
2023-04-16 19:59:53 +12:00
if ( ! isset ( $dir ) || ! file_exists ( $dir )) {
2011-10-14 12:48:00 +02:00
// plugin broken or does not exist, do not bother with printing of debug message
return $capabilityname . ' ???' ;
}
// something is wrong in plugin, better print debug
return get_string ( $stringname , $component );
}
/**
* This gets the mod / block / course / core etc strings .
*
* @ param string $component
* @ param int $contextlevel
* @ return string | bool String is success , false if failed
*/
function get_component_string ( $component , $contextlevel ) {
2019-10-10 12:32:09 +01:00
if ( $component === 'moodle' || $component === 'core' ) {
return context_helper :: get_level_name ( $contextlevel );
2011-10-14 12:48:00 +02:00
}
2013-07-16 22:41:00 +02:00
list ( $type , $name ) = core_component :: normalize_component ( $component );
2013-07-16 22:38:38 +02:00
$dir = core_component :: get_plugin_directory ( $type , $name );
2023-04-16 19:59:53 +12:00
if ( ! isset ( $dir ) || ! file_exists ( $dir )) {
2011-10-14 12:48:00 +02:00
// plugin not installed, bad luck, there is no way to find the name
2019-10-10 12:32:09 +01:00
return $component . ' ???' ;
2011-10-14 12:48:00 +02:00
}
2019-10-10 12:32:09 +01:00
// Some plugin types need an extra prefix to make the name easy to understand.
2011-10-14 12:48:00 +02:00
switch ( $type ) {
2019-10-10 12:32:09 +01:00
case 'quiz' :
$prefix = get_string ( 'quizreport' , 'quiz' ) . ': ' ;
break ;
case 'repository' :
$prefix = get_string ( 'repository' , 'repository' ) . ': ' ;
break ;
case 'gradeimport' :
$prefix = get_string ( 'gradeimport' , 'grades' ) . ': ' ;
break ;
case 'gradeexport' :
$prefix = get_string ( 'gradeexport' , 'grades' ) . ': ' ;
break ;
case 'gradereport' :
$prefix = get_string ( 'gradereport' , 'grades' ) . ': ' ;
break ;
case 'webservice' :
$prefix = get_string ( 'webservice' , 'webservice' ) . ': ' ;
break ;
case 'block' :
$prefix = get_string ( 'block' ) . ': ' ;
break ;
2011-10-14 12:48:00 +02:00
case 'mod' :
2019-10-10 12:32:09 +01:00
$prefix = get_string ( 'activity' ) . ': ' ;
break ;
// Default case, just use the plugin name.
default :
$prefix = '' ;
2011-10-14 12:48:00 +02:00
}
2019-10-10 12:32:09 +01:00
return $prefix . get_string ( 'pluginname' , $component );
2011-10-14 12:48:00 +02:00
}
/**
* Gets the list of roles assigned to this context and up ( parents )
2017-09-11 11:19:03 +08:00
* from the aggregation of :
* a ) the list of roles that are visible on user profile page and participants page ( profileroles setting ) and ;
2017-09-21 19:49:19 +08:00
* b ) if applicable , those roles that are assigned in the context .
2011-10-14 12:48:00 +02:00
*
* @ param context $context
* @ return array
*/
function get_profile_roles ( context $context ) {
global $CFG , $DB ;
2017-09-21 19:49:19 +08:00
// If the current user can assign roles, then they can see all roles on the profile and participants page,
// provided the roles are assigned to at least 1 user in the context. If not, only the policy-defined roles.
if ( has_capability ( 'moodle/role:assign' , $context )) {
$rolesinscope = array_keys ( get_all_roles ( $context ));
} else {
$rolesinscope = empty ( $CFG -> profileroles ) ? [] : array_map ( 'trim' , explode ( ',' , $CFG -> profileroles ));
}
2017-09-11 11:19:03 +08:00
if ( empty ( $rolesinscope )) {
return [];
2011-10-14 12:48:00 +02:00
}
2017-09-11 11:19:03 +08:00
list ( $rallowed , $params ) = $DB -> get_in_or_equal ( $rolesinscope , SQL_PARAMS_NAMED , 'a' );
2011-10-14 12:48:00 +02:00
list ( $contextlist , $cparams ) = $DB -> get_in_or_equal ( $context -> get_parent_context_ids ( true ), SQL_PARAMS_NAMED , 'p' );
$params = array_merge ( $params , $cparams );
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ;
}
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, rn.name AS coursealias
2011-10-14 12:48:00 +02:00
FROM { role_assignments } ra , { role } r
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
WHERE r . id = ra . roleid
AND ra . contextid $contextlist
AND r . id $rallowed
ORDER BY r . sortorder ASC " ;
return $DB -> get_records_sql ( $sql , $params );
}
/**
* Gets the list of roles assigned to this context and up ( parents )
*
* @ param context $context
2018-07-29 22:43:06 +02:00
* @ param boolean $includeparents , false means without parents .
2011-10-14 12:48:00 +02:00
* @ return array
*/
2018-07-29 22:43:06 +02:00
function get_roles_used_in_context ( context $context , $includeparents = true ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2018-07-29 22:43:06 +02:00
if ( $includeparents === true ) {
list ( $contextlist , $params ) = $DB -> get_in_or_equal ( $context -> get_parent_context_ids ( true ), SQL_PARAMS_NAMED , 'cl' );
} else {
list ( $contextlist , $params ) = $DB -> get_in_or_equal ( $context -> id , SQL_PARAMS_NAMED , 'cl' );
}
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ;
}
2011-10-14 12:48:00 +02:00
2012-05-18 11:40:35 +02:00
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, rn.name AS coursealias
2011-10-14 12:48:00 +02:00
FROM { role_assignments } ra , { role } r
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
WHERE r . id = ra . roleid
AND ra . contextid $contextlist
ORDER BY r . sortorder ASC " ;
return $DB -> get_records_sql ( $sql , $params );
}
/**
* This function is used to print roles column in user profile page .
* It is using the CFG -> profileroles to limit the list to only interesting roles .
* ( The permission tab has full details of user role assignments . )
*
* @ param int $userid
* @ param int $courseid
* @ return string
*/
function get_user_roles_in_course ( $userid , $courseid ) {
global $CFG , $DB ;
if ( $courseid == SITEID ) {
$context = context_system :: instance ();
} else {
$context = context_course :: instance ( $courseid );
}
2017-09-21 19:49:19 +08:00
// If the current user can assign roles, then they can see all roles on the profile and participants page,
// provided the roles are assigned to at least 1 user in the context. If not, only the policy-defined roles.
if ( has_capability ( 'moodle/role:assign' , $context )) {
$rolesinscope = array_keys ( get_all_roles ( $context ));
} else {
$rolesinscope = empty ( $CFG -> profileroles ) ? [] : array_map ( 'trim' , explode ( ',' , $CFG -> profileroles ));
}
2017-09-14 14:10:48 +08:00
if ( empty ( $rolesinscope )) {
return '' ;
}
2011-10-14 12:48:00 +02:00
2017-09-14 14:10:48 +08:00
list ( $rallowed , $params ) = $DB -> get_in_or_equal ( $rolesinscope , SQL_PARAMS_NAMED , 'a' );
2011-10-14 12:48:00 +02:00
list ( $contextlist , $cparams ) = $DB -> get_in_or_equal ( $context -> get_parent_context_ids ( true ), SQL_PARAMS_NAMED , 'p' );
$params = array_merge ( $params , $cparams );
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ;
}
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, rn.name AS coursealias
2011-10-14 12:48:00 +02:00
FROM { role_assignments } ra , { role } r
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
WHERE r . id = ra . roleid
AND ra . contextid $contextlist
AND r . id $rallowed
AND ra . userid = : userid
ORDER BY r . sortorder ASC " ;
$params [ 'userid' ] = $userid ;
$rolestring = '' ;
if ( $roles = $DB -> get_records_sql ( $sql , $params )) {
2017-11-15 15:08:10 +00:00
$viewableroles = get_viewable_roles ( $context , $userid );
2011-10-14 12:48:00 +02:00
2017-11-15 15:08:10 +00:00
$rolenames = array ();
foreach ( $roles as $roleid => $unused ) {
if ( isset ( $viewableroles [ $roleid ])) {
$url = new moodle_url ( '/user/index.php' , [ 'contextid' => $context -> id , 'roleid' => $roleid ]);
$rolenames [] = '<a href="' . $url . '">' . $viewableroles [ $roleid ] . '</a>' ;
}
2011-10-14 12:48:00 +02:00
}
2021-01-12 08:05:28 +00:00
$rolestring = implode ( ', ' , $rolenames );
2011-10-14 12:48:00 +02:00
}
return $rolestring ;
}
/**
* Checks if a user can assign users to a particular role in this context
*
* @ param context $context
* @ param int $targetroleid - the id of the role you want to assign users to
* @ return boolean
*/
function user_can_assign ( context $context , $targetroleid ) {
global $DB ;
2012-12-06 10:52:09 +08:00
// First check to see if the user is a site administrator.
if ( is_siteadmin ()) {
return true ;
}
// Check if user has override capability.
// If not return false.
2011-10-14 12:48:00 +02:00
if ( ! has_capability ( 'moodle/role:assign' , $context )) {
return false ;
}
// pull out all active roles of this user from this context(or above)
if ( $userroles = get_user_roles ( $context )) {
foreach ( $userroles as $userrole ) {
// if any in the role_allow_override table, then it's ok
if ( $DB -> get_record ( 'role_allow_assign' , array ( 'roleid' => $userrole -> roleid , 'allowassign' => $targetroleid ))) {
return true ;
}
}
}
return false ;
}
/**
* Returns all site roles in correct sort order .
*
2013-04-07 17:39:29 +02:00
* Note : this method does not localise role names or descriptions ,
* use role_get_names () if you need role names .
*
2012-05-18 11:40:35 +02:00
* @ param context $context optional context for course role name aliases
* @ return array of role records with optional coursealias property
2011-10-14 12:48:00 +02:00
*/
2012-05-18 11:40:35 +02:00
function get_all_roles ( context $context = null ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2012-05-18 11:40:35 +02:00
if ( ! $context or ! $coursecontext = $context -> get_course_context ( false )) {
$coursecontext = null ;
}
if ( $coursecontext ) {
$sql = " SELECT r.*, rn.name AS coursealias
FROM { role } r
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
ORDER BY r . sortorder ASC " ;
return $DB -> get_records_sql ( $sql , array ( 'coursecontext' => $coursecontext -> id ));
} else {
return $DB -> get_records ( 'role' , array (), 'sortorder ASC' );
}
2011-10-14 12:48:00 +02:00
}
/**
* Returns roles of a specified archetype
*
* @ param string $archetype
* @ return array of full role records
*/
function get_archetype_roles ( $archetype ) {
global $DB ;
return $DB -> get_records ( 'role' , array ( 'archetype' => $archetype ), 'sortorder ASC' );
}
2017-07-26 11:20:35 +08:00
/**
* Gets all the user roles assigned in this context , or higher contexts for a list of users .
*
2018-05-14 15:26:04 +01:00
* If you try using the combination $userids = [], $checkparentcontexts = true then this is likely
* to cause an out - of - memory error on large Moodle sites , so this combination is deprecated and
* outputs a warning , even though it is the default .
*
2017-07-26 11:20:35 +08:00
* @ param context $context
* @ param array $userids . An empty list means fetch all role assignments for the context .
* @ param bool $checkparentcontexts defaults to true
* @ param string $order defaults to 'c.contextlevel DESC, r.sortorder ASC'
* @ return array
*/
function get_users_roles ( context $context , $userids = [], $checkparentcontexts = true , $order = 'c.contextlevel DESC, r.sortorder ASC' ) {
2018-05-14 15:26:04 +01:00
global $DB ;
if ( ! $userids && $checkparentcontexts ) {
debugging ( 'Please do not call get_users_roles() with $checkparentcontexts = true ' .
'and $userids array not set. This combination causes large Moodle sites ' .
'with lots of site-wide role assignemnts to run out of memory.' , DEBUG_DEVELOPER );
}
2017-07-26 11:20:35 +08:00
if ( $checkparentcontexts ) {
$contextids = $context -> get_parent_context_ids ();
} else {
$contextids = array ();
}
$contextids [] = $context -> id ;
list ( $contextids , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_NAMED , 'con' );
// If userids was passed as an empty array, we fetch all role assignments for the course.
if ( empty ( $userids )) {
$useridlist = ' IS NOT NULL ' ;
$uparams = [];
} else {
list ( $useridlist , $uparams ) = $DB -> get_in_or_equal ( $userids , SQL_PARAMS_NAMED , 'uids' );
}
$sql = " SELECT ra.*, r.name, r.shortname, ra.userid
FROM { role_assignments } ra , { role } r , { context } c
WHERE ra . userid $useridlist
AND ra . roleid = r . id
AND ra . contextid = c . id
AND ra . contextid $contextids
ORDER BY $order " ;
$all = $DB -> get_records_sql ( $sql , array_merge ( $params , $uparams ));
// Return results grouped by userid.
$result = [];
foreach ( $all as $id => $record ) {
if ( ! isset ( $result [ $record -> userid ])) {
$result [ $record -> userid ] = [];
}
$result [ $record -> userid ][ $record -> id ] = $record ;
}
// Make sure all requested users are included in the result, even if they had no role assignments.
foreach ( $userids as $id ) {
if ( ! isset ( $result [ $id ])) {
$result [ $id ] = [];
}
}
return $result ;
}
2011-10-14 12:48:00 +02:00
/**
* Gets all the user roles assigned in this context , or higher contexts
* this is mainly used when checking if a user can assign a role , or overriding a role
* i . e . we need to know what this user holds , in order to verify against allow_assign and
* allow_override tables
*
* @ param context $context
* @ param int $userid
* @ param bool $checkparentcontexts defaults to true
* @ param string $order defaults to 'c.contextlevel DESC, r.sortorder ASC'
* @ return array
*/
function get_user_roles ( context $context , $userid = 0 , $checkparentcontexts = true , $order = 'c.contextlevel DESC, r.sortorder ASC' ) {
global $USER , $DB ;
if ( empty ( $userid )) {
if ( empty ( $USER -> id )) {
return array ();
}
$userid = $USER -> id ;
}
if ( $checkparentcontexts ) {
$contextids = $context -> get_parent_context_ids ();
} else {
$contextids = array ();
}
$contextids [] = $context -> id ;
list ( $contextids , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_QM );
array_unshift ( $params , $userid );
$sql = " SELECT ra.*, r.name, r.shortname
FROM { role_assignments } ra , { role } r , { context } c
WHERE ra . userid = ?
AND ra . roleid = r . id
AND ra . contextid = c . id
AND ra . contextid $contextids
ORDER BY $order " ;
return $DB -> get_records_sql ( $sql , $params );
}
2012-07-06 12:20:01 +01:00
/**
* Like get_user_roles , but adds in the authenticated user role , and the front
* page roles , if applicable .
*
* @ param context $context the context .
* @ param int $userid optional . Defaults to $USER -> id
* @ return array of objects with fields -> userid , -> contextid and -> roleid .
*/
function get_user_roles_with_special ( context $context , $userid = 0 ) {
global $CFG , $USER ;
if ( empty ( $userid )) {
if ( empty ( $USER -> id )) {
return array ();
}
$userid = $USER -> id ;
}
$ras = get_user_roles ( $context , $userid );
// Add front-page role if relevant.
$defaultfrontpageroleid = isset ( $CFG -> defaultfrontpageroleid ) ? $CFG -> defaultfrontpageroleid : 0 ;
$isfrontpage = ( $context -> contextlevel == CONTEXT_COURSE && $context -> instanceid == SITEID ) ||
is_inside_frontpage ( $context );
if ( $defaultfrontpageroleid && $isfrontpage ) {
$frontpagecontext = context_course :: instance ( SITEID );
$ra = new stdClass ();
$ra -> userid = $userid ;
$ra -> contextid = $frontpagecontext -> id ;
$ra -> roleid = $defaultfrontpageroleid ;
$ras [] = $ra ;
}
// Add authenticated user role if relevant.
$defaultuserroleid = isset ( $CFG -> defaultuserroleid ) ? $CFG -> defaultuserroleid : 0 ;
if ( $defaultuserroleid && ! isguestuser ( $userid )) {
$systemcontext = context_system :: instance ();
$ra = new stdClass ();
$ra -> userid = $userid ;
$ra -> contextid = $systemcontext -> id ;
$ra -> roleid = $defaultuserroleid ;
$ras [] = $ra ;
}
return $ras ;
}
2011-10-14 12:48:00 +02:00
/**
* Creates a record in the role_allow_override table
*
2017-11-24 12:30:40 +00:00
* @ param int $fromroleid source roleid
* @ param int $targetroleid target roleid
2011-10-14 12:48:00 +02:00
* @ return void
*/
2017-11-24 12:30:40 +00:00
function core_role_set_override_allowed ( $fromroleid , $targetroleid ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$record = new stdClass ();
2017-11-24 12:30:40 +00:00
$record -> roleid = $fromroleid ;
$record -> allowoverride = $targetroleid ;
2011-10-14 12:48:00 +02:00
$DB -> insert_record ( 'role_allow_override' , $record );
}
/**
* Creates a record in the role_allow_assign table
*
* @ param int $fromroleid source roleid
* @ param int $targetroleid target roleid
* @ return void
*/
2017-11-24 12:30:40 +00:00
function core_role_set_assign_allowed ( $fromroleid , $targetroleid ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$record = new stdClass ();
$record -> roleid = $fromroleid ;
$record -> allowassign = $targetroleid ;
$DB -> insert_record ( 'role_allow_assign' , $record );
}
/**
* Creates a record in the role_allow_switch table
*
* @ param int $fromroleid source roleid
* @ param int $targetroleid target roleid
* @ return void
*/
2017-11-24 12:30:40 +00:00
function core_role_set_switch_allowed ( $fromroleid , $targetroleid ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$record = new stdClass ();
$record -> roleid = $fromroleid ;
$record -> allowswitch = $targetroleid ;
$DB -> insert_record ( 'role_allow_switch' , $record );
}
2017-11-15 15:08:10 +00:00
/**
* Creates a record in the role_allow_view table
*
* @ param int $fromroleid source roleid
* @ param int $targetroleid target roleid
* @ return void
*/
function core_role_set_view_allowed ( $fromroleid , $targetroleid ) {
global $DB ;
$record = new stdClass ();
$record -> roleid = $fromroleid ;
$record -> allowview = $targetroleid ;
$DB -> insert_record ( 'role_allow_view' , $record );
}
2011-10-14 12:48:00 +02:00
/**
* Gets a list of roles that this user can assign in this context
*
* @ param context $context the context .
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
* @ param bool $withusercounts if true , count the number of users with each role .
* @ param integer | object $user A user id or object . By default ( null ) checks the permissions of the current user .
* @ return array if $withusercounts is false , then an array $roleid => $rolename .
* if $withusercounts is true , returns a list of three arrays ,
* $rolenames , $rolecounts , and $nameswithcounts .
*/
function get_assignable_roles ( context $context , $rolenamedisplay = ROLENAME_ALIAS , $withusercounts = false , $user = null ) {
global $USER , $DB ;
// make sure there is a real user specified
if ( $user === null ) {
$userid = isset ( $USER -> id ) ? $USER -> id : 0 ;
} else {
$userid = is_object ( $user ) ? $user -> id : $user ;
}
if ( ! has_capability ( 'moodle/role:assign' , $context , $userid )) {
if ( $withusercounts ) {
return array ( array (), array (), array ());
} else {
return array ();
}
}
$params = array ();
$extrafields = '' ;
if ( $withusercounts ) {
2019-03-08 12:32:24 +00:00
$extrafields = ' , ( SELECT COUNT ( DISTINCT u . id )
2011-10-14 12:48:00 +02:00
FROM { role_assignments } cra JOIN { user } u ON cra . userid = u . id
WHERE cra . roleid = r . id AND cra . contextid = : conid AND u . deleted = 0
) AS usercount ' ;
$params [ 'conid' ] = $context -> id ;
}
if ( is_siteadmin ( $userid )) {
// show all roles allowed in this context to admins
$assignrestriction = " " ;
} else {
2012-05-18 11:40:35 +02:00
$parents = $context -> get_parent_context_ids ( true );
$contexts = implode ( ',' , $parents );
2011-10-14 12:48:00 +02:00
$assignrestriction = " JOIN (SELECT DISTINCT raa.allowassign AS id
FROM { role_allow_assign } raa
JOIN { role_assignments } ra ON ra . roleid = raa . roleid
WHERE ra . userid = : userid AND ra . contextid IN ( $contexts )
) ar ON ar . id = r . id " ;
$params [ 'userid' ] = $userid ;
}
$params [ 'contextlevel' ] = $context -> contextlevel ;
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ; // no course aliases
$coursecontext = null ;
}
$sql = " SELECT r.id, r.name, r.shortname, rn.name AS coursealias $extrafields
2011-10-14 12:48:00 +02:00
FROM { role } r
$assignrestriction
2012-05-18 11:40:35 +02:00
JOIN { role_context_levels } rcl ON ( rcl . contextlevel = : contextlevel AND r . id = rcl . roleid )
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
ORDER BY r . sortorder ASC " ;
$roles = $DB -> get_records_sql ( $sql , $params );
2012-05-18 11:40:35 +02:00
$rolenames = role_fix_names ( $roles , $coursecontext , $rolenamedisplay , true );
2011-10-14 12:48:00 +02:00
if ( ! $withusercounts ) {
return $rolenames ;
}
$rolecounts = array ();
$nameswithcounts = array ();
foreach ( $roles as $role ) {
$nameswithcounts [ $role -> id ] = $rolenames [ $role -> id ] . ' (' . $roles [ $role -> id ] -> usercount . ')' ;
$rolecounts [ $role -> id ] = $roles [ $role -> id ] -> usercount ;
}
return array ( $rolenames , $rolecounts , $nameswithcounts );
}
/**
* Gets a list of roles that this user can switch to in a context
*
* Gets a list of roles that this user can switch to in a context , for the switchrole menu .
* This function just process the contents of the role_allow_switch table . You also need to
* test the moodle / role : switchroles to see if the user is allowed to switch in the first place .
*
* @ param context $context a context .
2019-03-27 16:03:00 +00:00
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
2011-10-14 12:48:00 +02:00
* @ return array an array $roleid => $rolename .
*/
2019-03-27 16:03:00 +00:00
function get_switchable_roles ( context $context , $rolenamedisplay = ROLENAME_ALIAS ) {
2011-10-14 12:48:00 +02:00
global $USER , $DB ;
2016-11-24 15:01:55 +08:00
// You can't switch roles without this capability.
if ( ! has_capability ( 'moodle/role:switchroles' , $context )) {
return [];
}
2011-10-14 12:48:00 +02:00
$params = array ();
$extrajoins = '' ;
$extrawhere = '' ;
if ( ! is_siteadmin ()) {
// Admins are allowed to switch to any role with.
// Others are subject to the additional constraint that the switch-to role must be allowed by
// 'role_allow_switch' for some role they have assigned in this context or any parent.
$parents = $context -> get_parent_context_ids ( true );
$contexts = implode ( ',' , $parents );
$extrajoins = " JOIN { role_allow_switch} ras ON ras.allowswitch = rc.roleid
JOIN { role_assignments } ra ON ra . roleid = ras . roleid " ;
$extrawhere = " WHERE ra.userid = :userid AND ra.contextid IN ( $contexts ) " ;
$params [ 'userid' ] = $USER -> id ;
}
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ; // no course aliases
$coursecontext = null ;
}
2011-10-14 12:48:00 +02:00
$query = "
2012-05-18 11:40:35 +02:00
SELECT r . id , r . name , r . shortname , rn . name AS coursealias
2011-10-14 12:48:00 +02:00
FROM ( SELECT DISTINCT rc . roleid
FROM { role_capabilities } rc
2019-02-28 08:39:20 +08:00
2011-10-14 12:48:00 +02:00
$extrajoins
$extrawhere ) idlist
JOIN { role } r ON r . id = idlist . roleid
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
ORDER BY r . sortorder " ;
2012-05-18 11:40:35 +02:00
$roles = $DB -> get_records_sql ( $query , $params );
2011-10-14 12:48:00 +02:00
2019-03-27 16:03:00 +00:00
return role_fix_names ( $roles , $context , $rolenamedisplay , true );
2011-10-14 12:48:00 +02:00
}
2017-11-15 15:08:10 +00:00
/**
* Gets a list of roles that this user can view in a context
*
* @ param context $context a context .
* @ param int $userid id of user .
2019-03-27 16:03:00 +00:00
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
2017-11-15 15:08:10 +00:00
* @ return array an array $roleid => $rolename .
*/
2019-03-27 16:03:00 +00:00
function get_viewable_roles ( context $context , $userid = null , $rolenamedisplay = ROLENAME_ALIAS ) {
2017-11-15 15:08:10 +00:00
global $USER , $DB ;
if ( $userid == null ) {
$userid = $USER -> id ;
}
$params = array ();
$extrajoins = '' ;
$extrawhere = '' ;
if ( ! is_siteadmin ()) {
// Admins are allowed to view any role.
// Others are subject to the additional constraint that the view role must be allowed by
// 'role_allow_view' for some role they have assigned in this context or any parent.
$contexts = $context -> get_parent_context_ids ( true );
list ( $insql , $inparams ) = $DB -> get_in_or_equal ( $contexts , SQL_PARAMS_NAMED );
$extrajoins = " JOIN { role_allow_view} ras ON ras.allowview = r.id
JOIN { role_assignments } ra ON ra . roleid = ras . roleid " ;
$extrawhere = " WHERE ra.userid = :userid AND ra.contextid $insql " ;
$params += $inparams ;
$params [ 'userid' ] = $userid ;
}
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ; // No course aliases.
$coursecontext = null ;
}
$query = "
2017-12-20 15:43:19 +13:00
SELECT r . id , r . name , r . shortname , rn . name AS coursealias , r . sortorder
2017-11-15 15:08:10 +00:00
FROM { role } r
$extrajoins
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
$extrawhere
2017-12-20 15:43:19 +13:00
GROUP BY r . id , r . name , r . shortname , rn . name , r . sortorder
2017-11-15 15:08:10 +00:00
ORDER BY r . sortorder " ;
$roles = $DB -> get_records_sql ( $query , $params );
2019-03-27 16:03:00 +00:00
return role_fix_names ( $roles , $context , $rolenamedisplay , true );
2017-11-15 15:08:10 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Gets a list of roles that this user can override in this context .
*
* @ param context $context the context .
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
* @ param bool $withcounts if true , count the number of overrides that are set for each role .
* @ return array if $withcounts is false , then an array $roleid => $rolename .
* if $withusercounts is true , returns a list of three arrays ,
* $rolenames , $rolecounts , and $nameswithcounts .
*/
function get_overridable_roles ( context $context , $rolenamedisplay = ROLENAME_ALIAS , $withcounts = false ) {
global $USER , $DB ;
if ( ! has_any_capability ( array ( 'moodle/role:safeoverride' , 'moodle/role:override' ), $context )) {
if ( $withcounts ) {
return array ( array (), array (), array ());
} else {
return array ();
}
}
$parents = $context -> get_parent_context_ids ( true );
$contexts = implode ( ',' , $parents );
$params = array ();
$extrafields = '' ;
$params [ 'userid' ] = $USER -> id ;
if ( $withcounts ) {
$extrafields = ' , ( SELECT COUNT ( rc . id ) FROM { role_capabilities } rc
WHERE rc . roleid = ro . id AND rc . contextid = : conid ) AS overridecount ' ;
$params [ 'conid' ] = $context -> id ;
}
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ; // no course aliases
$coursecontext = null ;
}
2011-10-14 12:48:00 +02:00
if ( is_siteadmin ()) {
// show all roles to admins
$roles = $DB -> get_records_sql ( "
2012-05-18 11:40:35 +02:00
SELECT ro . id , ro . name , ro . shortname , rn . name AS coursealias $extrafields
2011-10-14 12:48:00 +02:00
FROM { role } ro
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = ro . id )
2011-10-14 12:48:00 +02:00
ORDER BY ro . sortorder ASC " , $params );
} else {
$roles = $DB -> get_records_sql ( "
2012-05-18 11:40:35 +02:00
SELECT ro . id , ro . name , ro . shortname , rn . name AS coursealias $extrafields
2011-10-14 12:48:00 +02:00
FROM { role } ro
JOIN ( SELECT DISTINCT r . id
FROM { role } r
JOIN { role_allow_override } rao ON r . id = rao . allowoverride
JOIN { role_assignments } ra ON rao . roleid = ra . roleid
WHERE ra . userid = : userid AND ra . contextid IN ( $contexts )
) inline_view ON ro . id = inline_view . id
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = ro . id )
2011-10-14 12:48:00 +02:00
ORDER BY ro . sortorder ASC " , $params );
}
2012-05-18 11:40:35 +02:00
$rolenames = role_fix_names ( $roles , $context , $rolenamedisplay , true );
2011-10-14 12:48:00 +02:00
if ( ! $withcounts ) {
return $rolenames ;
2012-05-18 11:40:35 +02:00
}
2011-10-14 12:48:00 +02:00
$rolecounts = array ();
$nameswithcounts = array ();
foreach ( $roles as $role ) {
$nameswithcounts [ $role -> id ] = $rolenames [ $role -> id ] . ' (' . $roles [ $role -> id ] -> overridecount . ')' ;
$rolecounts [ $role -> id ] = $roles [ $role -> id ] -> overridecount ;
}
return array ( $rolenames , $rolecounts , $nameswithcounts );
}
/**
* Create a role menu suitable for default role selection in enrol plugins .
2012-01-14 19:12:43 +01:00
*
* @ package core_enrol
*
2011-10-14 12:48:00 +02:00
* @ param context $context
* @ param int $addroleid current or default role - always added to list
* @ return array roleid => localised role name
*/
function get_default_enrol_roles ( context $context , $addroleid = null ) {
global $DB ;
$params = array ( 'contextlevel' => CONTEXT_COURSE );
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ; // no course names
$coursecontext = null ;
}
2011-10-14 12:48:00 +02:00
if ( $addroleid ) {
$addrole = " OR r.id = :addroleid " ;
$params [ 'addroleid' ] = $addroleid ;
} else {
$addrole = " " ;
}
2012-05-18 11:40:35 +02:00
$sql = " SELECT r.id, r.name, r.shortname, rn.name AS coursealias
2011-10-14 12:48:00 +02:00
FROM { role } r
LEFT JOIN { role_context_levels } rcl ON ( rcl . roleid = r . id AND rcl . contextlevel = : contextlevel )
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
WHERE rcl . id IS NOT NULL $addrole
2014-09-10 11:18:52 +08:00
ORDER BY sortorder DESC " ;
2011-10-14 12:48:00 +02:00
2012-05-18 11:40:35 +02:00
$roles = $DB -> get_records_sql ( $sql , $params );
2011-10-14 12:48:00 +02:00
2012-05-18 11:40:35 +02:00
return role_fix_names ( $roles , $context , ROLENAME_BOTH , true );
2011-10-14 12:48:00 +02:00
}
/**
* Return context levels where this role is assignable .
2012-01-14 19:12:43 +01:00
*
2011-10-14 12:48:00 +02:00
* @ param integer $roleid the id of a role .
* @ return array list of the context levels at which this role may be assigned .
*/
function get_role_contextlevels ( $roleid ) {
global $DB ;
return $DB -> get_records_menu ( 'role_context_levels' , array ( 'roleid' => $roleid ),
'contextlevel' , 'id,contextlevel' );
}
/**
* Return roles suitable for assignment at the specified context level .
*
* NOTE : this function name looks like a typo , should be probably get_roles_for_contextlevel ()
*
* @ param integer $contextlevel a contextlevel .
* @ return array list of role ids that are assignable at this context level .
*/
function get_roles_for_contextlevels ( $contextlevel ) {
global $DB ;
return $DB -> get_records_menu ( 'role_context_levels' , array ( 'contextlevel' => $contextlevel ),
'' , 'id,roleid' );
}
/**
* Returns default context levels where roles can be assigned .
*
* @ param string $rolearchetype one of the role archetypes - that is , one of the keys
* from the array returned by get_role_archetypes ();
* @ return array list of the context levels at which this type of role may be assigned by default .
*/
function get_default_contextlevels ( $rolearchetype ) {
static $defaults = array (
'manager' => array ( CONTEXT_SYSTEM , CONTEXT_COURSECAT , CONTEXT_COURSE ),
'coursecreator' => array ( CONTEXT_SYSTEM , CONTEXT_COURSECAT ),
'editingteacher' => array ( CONTEXT_COURSE , CONTEXT_MODULE ),
'teacher' => array ( CONTEXT_COURSE , CONTEXT_MODULE ),
'student' => array ( CONTEXT_COURSE , CONTEXT_MODULE ),
'guest' => array (),
'user' => array (),
'frontpage' => array ());
if ( isset ( $defaults [ $rolearchetype ])) {
return $defaults [ $rolearchetype ];
} else {
return array ();
}
}
/**
* Set the context levels at which a particular role can be assigned .
* Throws exceptions in case of error .
*
* @ param integer $roleid the id of a role .
* @ param array $contextlevels the context levels at which this role should be assignable ,
* duplicate levels are removed .
* @ return void
*/
function set_role_contextlevels ( $roleid , array $contextlevels ) {
global $DB ;
$DB -> delete_records ( 'role_context_levels' , array ( 'roleid' => $roleid ));
$rcl = new stdClass ();
$rcl -> roleid = $roleid ;
$contextlevels = array_unique ( $contextlevels );
foreach ( $contextlevels as $level ) {
$rcl -> contextlevel = $level ;
$DB -> insert_record ( 'role_context_levels' , $rcl , false , true );
}
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
/**
2020-04-14 17:06:13 +01:00
* Gets sql joins for finding users with capability in the given context .
2011-10-14 12:48:00 +02:00
*
2020-04-14 17:06:13 +01:00
* @ param context $context Context for the join .
* @ param string | array $capability Capability name or array of names .
* If an array is provided then this is the equivalent of a logical 'OR' ,
* i . e . the user needs to have one of these capabilities .
* @ param string $useridcolumn e . g . 'u.id' .
* @ return \core\dml\sql_join Contains joins , wheres , params .
* This function will set -> cannotmatchanyrows if applicable .
* This may let you skip doing a DB query .
2011-10-14 12:48:00 +02:00
*/
2020-04-14 17:06:13 +01:00
function get_with_capability_join ( context $context , $capability , $useridcolumn ) {
2011-10-14 12:48:00 +02:00
global $CFG , $DB ;
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2020-04-14 17:06:13 +01:00
// Add a unique prefix to param names to ensure they are unique.
static $i = 0 ;
$i ++ ;
$paramprefix = 'eu' . $i . '_' ;
2011-10-14 12:48:00 +02:00
$defaultuserroleid = isset ( $CFG -> defaultuserroleid ) ? $CFG -> defaultuserroleid : 0 ;
$defaultfrontpageroleid = isset ( $CFG -> defaultfrontpageroleid ) ? $CFG -> defaultfrontpageroleid : 0 ;
$ctxids = trim ( $context -> path , '/' );
$ctxids = str_replace ( '/' , ',' , $ctxids );
// Context is the frontpage
2020-04-14 17:06:13 +01:00
$isfrontpage = $context -> contextlevel == CONTEXT_COURSE && $context -> instanceid == SITEID ;
$isfrontpage = $isfrontpage || is_inside_frontpage ( $context );
2010-03-31 07:41:31 +00:00
2020-04-14 22:29:17 +01:00
$caps = ( array ) $capability ;
2011-10-14 12:48:00 +02:00
2020-04-14 22:29:17 +01:00
// Construct list of context paths bottom --> top.
2011-10-14 12:48:00 +02:00
list ( $contextids , $paths ) = get_context_info_list ( $context );
2020-04-14 22:29:17 +01:00
// We need to find out all roles that have these capabilities either in definition or in overrides.
$defs = [];
2020-04-14 17:06:13 +01:00
list ( $incontexts , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_NAMED , $paramprefix . 'con' );
list ( $incaps , $params2 ) = $DB -> get_in_or_equal ( $caps , SQL_PARAMS_NAMED , $paramprefix . 'cap' );
2019-02-28 08:47:09 +08:00
// Check whether context locking is enabled.
// Filter out any write capability if this is the case.
$excludelockedcaps = '' ;
$excludelockedcapsparams = [];
if ( ! empty ( $CFG -> contextlocking ) && $context -> locked ) {
$excludelockedcaps = 'AND (cap.captype = :capread OR cap.name = :managelockscap)' ;
$excludelockedcapsparams [ 'capread' ] = 'read' ;
$excludelockedcapsparams [ 'managelockscap' ] = 'moodle/site:managecontextlocks' ;
}
$params = array_merge ( $params , $params2 , $excludelockedcapsparams );
2011-10-14 12:48:00 +02:00
$sql = " SELECT rc.id, rc.roleid, rc.permission, rc.capability, ctx.path
FROM { role_capabilities } rc
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
JOIN { context } ctx on rc . contextid = ctx . id
2019-02-28 08:47:09 +08:00
WHERE rc . contextid $incontexts AND rc . capability $incaps $excludelockedcaps " ;
2011-10-14 12:48:00 +02:00
$rcs = $DB -> get_records_sql ( $sql , $params );
foreach ( $rcs as $rc ) {
$defs [ $rc -> capability ][ $rc -> path ][ $rc -> roleid ] = $rc -> permission ;
}
2020-04-14 22:29:17 +01:00
// Go through the permissions bottom-->top direction to evaluate the current permission,
// first one wins (prohibit is an exception that always wins).
$access = [];
2011-10-14 12:48:00 +02:00
foreach ( $caps as $cap ) {
foreach ( $paths as $path ) {
if ( empty ( $defs [ $cap ][ $path ])) {
continue ;
}
2020-05-06 09:14:49 +01:00
foreach ( $defs [ $cap ][ $path ] as $roleid => $perm ) {
2011-10-14 12:48:00 +02:00
if ( $perm == CAP_PROHIBIT ) {
$access [ $cap ][ $roleid ] = CAP_PROHIBIT ;
2010-03-31 07:41:31 +00:00
continue ;
}
2011-10-14 12:48:00 +02:00
if ( ! isset ( $access [ $cap ][ $roleid ])) {
$access [ $cap ][ $roleid ] = ( int ) $perm ;
2010-03-31 07:41:31 +00:00
}
}
}
2011-10-14 12:48:00 +02:00
}
2010-03-31 07:41:31 +00:00
2020-04-14 22:29:17 +01:00
// Make lists of roles that are needed and prohibited in this context.
$needed = []; // One of these is enough.
$prohibited = []; // Must not have any of these.
2011-10-14 12:48:00 +02:00
foreach ( $caps as $cap ) {
if ( empty ( $access [ $cap ])) {
continue ;
}
foreach ( $access [ $cap ] as $roleid => $perm ) {
2010-09-17 07:37:51 +00:00
if ( $perm == CAP_PROHIBIT ) {
2011-10-14 12:48:00 +02:00
unset ( $needed [ $cap ][ $roleid ]);
$prohibited [ $cap ][ $roleid ] = true ;
} else if ( $perm == CAP_ALLOW and empty ( $prohibited [ $cap ][ $roleid ])) {
$needed [ $cap ][ $roleid ] = true ;
2010-03-31 07:41:31 +00:00
}
}
2011-10-14 12:48:00 +02:00
if ( empty ( $needed [ $cap ]) or ! empty ( $prohibited [ $cap ][ $defaultuserroleid ])) {
2020-04-14 22:29:17 +01:00
// Easy, nobody has the permission.
2011-10-14 12:48:00 +02:00
unset ( $needed [ $cap ]);
unset ( $prohibited [ $cap ]);
} else if ( $isfrontpage and ! empty ( $prohibited [ $cap ][ $defaultfrontpageroleid ])) {
2020-04-14 22:29:17 +01:00
// Everybody is disqualified on the frontpage.
2011-10-14 12:48:00 +02:00
unset ( $needed [ $cap ]);
unset ( $prohibited [ $cap ]);
}
if ( empty ( $prohibited [ $cap ])) {
unset ( $prohibited [ $cap ]);
}
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
if ( empty ( $needed )) {
2020-04-14 22:29:17 +01:00
// There can not be anybody if no roles match this request.
2020-04-14 17:06:13 +01:00
return new \core\dml\sql_join ( '' , '1 = 2' , [], true );
2011-10-14 12:48:00 +02:00
}
if ( empty ( $prohibited )) {
2020-04-14 22:29:17 +01:00
// We can compact the needed roles.
$n = [];
2011-10-14 12:48:00 +02:00
foreach ( $needed as $cap ) {
2020-04-14 22:29:17 +01:00
foreach ( $cap as $roleid => $unused ) {
2011-10-14 12:48:00 +02:00
$n [ $roleid ] = true ;
}
}
2020-04-14 22:29:17 +01:00
$needed = [ 'any' => $n ];
2011-10-14 12:48:00 +02:00
unset ( $n );
}
2020-04-14 22:29:17 +01:00
// Prepare query clauses.
$wherecond = [];
$params = [];
$joins = [];
$cannotmatchanyrows = false ;
2011-10-14 12:48:00 +02:00
2012-02-21 11:48:33 +13:00
// We never return deleted users or guest account.
2020-04-14 22:29:17 +01:00
// Use a hack to get the deleted user column without an API change.
$deletedusercolumn = substr ( $useridcolumn , 0 , - 2 ) . 'deleted' ;
2020-04-14 17:06:13 +01:00
$wherecond [] = " $deletedusercolumn = 0 AND $useridcolumn <> : { $paramprefix } guestid " ;
$params [ $paramprefix . 'guestid' ] = $CFG -> siteguest ;
2011-10-14 12:48:00 +02:00
2020-04-14 22:29:17 +01:00
// Now add the needed and prohibited roles conditions as joins.
2011-10-14 12:48:00 +02:00
if ( ! empty ( $needed [ 'any' ])) {
2020-04-14 22:29:17 +01:00
// Simple case - there are no prohibits involved.
if ( ! empty ( $needed [ 'any' ][ $defaultuserroleid ]) ||
( $isfrontpage && ! empty ( $needed [ 'any' ][ $defaultfrontpageroleid ]))) {
// Everybody.
2011-10-14 12:48:00 +02:00
} else {
$joins [] = " JOIN (SELECT DISTINCT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
2020-04-14 22:29:17 +01:00
AND roleid IN ( " . implode(',', array_keys( $needed['any'] )) . " )
2020-04-14 17:06:13 +01:00
) ra ON ra . userid = $useridcolumn " ;
2011-10-14 12:48:00 +02:00
}
} else {
2020-04-14 22:29:17 +01:00
$unions = [];
2011-10-14 12:48:00 +02:00
$everybody = false ;
2020-04-14 22:29:17 +01:00
foreach ( $needed as $cap => $unused ) {
2011-10-14 12:48:00 +02:00
if ( empty ( $prohibited [ $cap ])) {
2020-04-14 22:29:17 +01:00
if ( ! empty ( $needed [ $cap ][ $defaultuserroleid ]) ||
( $isfrontpage && ! empty ( $needed [ $cap ][ $defaultfrontpageroleid ]))) {
2011-10-14 12:48:00 +02:00
$everybody = true ;
break ;
} else {
$unions [] = " SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
AND roleid IN ( " .implode(',', array_keys( $needed[$cap] )) . " ) " ;
}
} else {
2020-04-14 22:29:17 +01:00
if ( ! empty ( $prohibited [ $cap ][ $defaultuserroleid ]) ||
( $isfrontpage && ! empty ( $prohibited [ $cap ][ $defaultfrontpageroleid ]))) {
// Nobody can have this cap because it is prohibited in default roles.
2011-10-14 12:48:00 +02:00
continue ;
2007-08-06 18:45:35 +00:00
2020-04-14 22:29:17 +01:00
} else if ( ! empty ( $needed [ $cap ][ $defaultuserroleid ]) ||
( $isfrontpage && ! empty ( $needed [ $cap ][ $defaultfrontpageroleid ]))) {
// Everybody except the prohibited - hiding does not matter.
2011-10-14 12:48:00 +02:00
$unions [] = " SELECT id AS userid
FROM { user }
WHERE id NOT IN ( SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
2020-04-14 22:29:17 +01:00
AND roleid IN ( " . implode(',', array_keys( $prohibited[$cap] )) . " )) " ;
2007-08-06 18:45:35 +00:00
2011-10-14 12:48:00 +02:00
} else {
2017-01-10 12:38:29 +05:30
$unions [] = " SELECT userid
FROM { role_assignments }
2020-04-14 22:29:17 +01:00
WHERE contextid IN ( $ctxids ) AND roleid IN ( " . implode(',', array_keys( $needed[$cap] )) . " )
2017-01-10 12:38:29 +05:30
AND userid NOT IN (
SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
2020-04-14 22:29:17 +01:00
AND roleid IN ( " . implode(',', array_keys( $prohibited[$cap] )) . " )) " ;
2011-10-14 12:48:00 +02:00
}
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
}
2020-04-14 22:29:17 +01:00
2011-10-14 12:48:00 +02:00
if ( ! $everybody ) {
if ( $unions ) {
2020-04-14 22:29:17 +01:00
$joins [] = " JOIN (
SELECT DISTINCT userid
FROM (
" . implode( " \n UNION \n " , $unions ) . "
) us
) ra ON ra . userid = $useridcolumn " ;
2011-10-14 12:48:00 +02:00
} else {
2020-04-14 22:29:17 +01:00
// Only prohibits found - nobody can be matched.
2011-10-14 12:48:00 +02:00
$wherecond [] = " 1 = 2 " ;
2020-04-14 22:29:17 +01:00
$cannotmatchanyrows = true ;
2006-09-13 08:07:14 +00:00
}
2006-09-13 06:35:25 +00:00
}
2011-10-14 12:48:00 +02:00
}
2006-09-17 08:42:42 +00:00
2020-04-14 22:29:17 +01:00
return new \core\dml\sql_join ( implode ( " \n " , $joins ), implode ( " AND " , $wherecond ), $params , $cannotmatchanyrows );
2020-04-14 17:06:13 +01:00
}
/**
* Who has this capability in this context ?
*
* This can be a very expensive call - use sparingly and keep
* the results if you are going to need them again soon .
*
* Note if $fields is empty this function attempts to get u .*
* which can get rather large - and has a serious perf impact
* on some DBs .
*
* @ param context $context
* @ param string | array $capability - capability name ( s )
* @ param string $fields - fields to be pulled . The user table is aliased to 'u' . u . id MUST be included .
* @ param string $sort - the sort order . Default is lastaccess time .
* @ param mixed $limitfrom - number of records to skip ( offset )
* @ param mixed $limitnum - number of records to fetch
* @ param string | array $groups - single group or array of groups - only return
* users who are in one of these group ( s ) .
* @ param string | array $exceptions - list of users to exclude , comma separated or array
2020-04-14 22:29:17 +01:00
* @ param bool $notuseddoanything not used any more , admin accounts are never returned
* @ param bool $notusedview - use get_enrolled_sql () instead
2020-04-14 17:06:13 +01:00
* @ param bool $useviewallgroups if $groups is set the return users who
* have capability both $capability and moodle / site : accessallgroups
* in this context , as well as users who have $capability and who are
* in $groups .
* @ return array of user records
*/
function get_users_by_capability ( context $context , $capability , $fields = '' , $sort = '' , $limitfrom = '' , $limitnum = '' ,
2020-04-14 22:29:17 +01:00
$groups = '' , $exceptions = '' , $notuseddoanything = null , $notusedview = null , $useviewallgroups = false ) {
2020-04-14 17:06:13 +01:00
global $CFG , $DB ;
2020-04-14 22:29:17 +01:00
// Context is a course page other than the frontpage.
2020-04-14 17:06:13 +01:00
$iscoursepage = $context -> contextlevel == CONTEXT_COURSE && $context -> instanceid != SITEID ;
2020-04-14 22:29:17 +01:00
// Set up default fields list if necessary.
2020-04-14 17:06:13 +01:00
if ( empty ( $fields )) {
if ( $iscoursepage ) {
$fields = 'u.*, ul.timeaccess AS lastaccess' ;
} else {
$fields = 'u.*' ;
}
} else {
if ( $CFG -> debugdeveloper && strpos ( $fields , 'u.*' ) === false && strpos ( $fields , 'u.id' ) === false ) {
debugging ( 'u.id must be included in the list of fields passed to get_users_by_capability().' , DEBUG_DEVELOPER );
}
}
2020-04-14 22:29:17 +01:00
// Set up default sort if necessary.
2020-04-14 17:06:13 +01:00
if ( empty ( $sort )) { // default to course lastaccess or just lastaccess
if ( $iscoursepage ) {
$sort = 'ul.timeaccess' ;
} else {
$sort = 'u.lastaccess' ;
}
}
2020-04-14 22:29:17 +01:00
// Get the bits of SQL relating to capabilities.
$sqljoin = get_with_capability_join ( $context , $capability , 'u.id' );
if ( $sqljoin -> cannotmatchanyrows ) {
return [];
}
// Prepare query clauses.
2020-04-14 17:06:13 +01:00
$wherecond = [ $sqljoin -> wheres ];
$params = $sqljoin -> params ;
$joins = [ $sqljoin -> joins ];
2020-04-14 22:29:17 +01:00
// Add user lastaccess JOIN, if required.
2020-04-14 17:06:13 +01:00
if (( strpos ( $sort , 'ul.timeaccess' ) === false ) and ( strpos ( $fields , 'ul.timeaccess' ) === false )) {
2020-04-14 22:29:17 +01:00
// Here user_lastaccess is not required MDL-13810.
2020-04-14 17:06:13 +01:00
} else {
if ( $iscoursepage ) {
$joins [] = " LEFT OUTER JOIN { user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = { $context -> instanceid } ) " ;
} else {
throw new coding_exception ( 'Invalid sort in get_users_by_capability(), ul.timeaccess allowed only for course contexts.' );
}
}
2020-04-14 22:29:17 +01:00
// Groups.
2020-04-14 17:06:13 +01:00
if ( $groups ) {
$groups = ( array ) $groups ;
list ( $grouptest , $grpparams ) = $DB -> get_in_or_equal ( $groups , SQL_PARAMS_NAMED , 'grp' );
$joins [] = " LEFT OUTER JOIN (SELECT DISTINCT userid
FROM { groups_members }
WHERE groupid $grouptest
) gm ON gm . userid = u . id " ;
$params = array_merge ( $params , $grpparams );
$grouptest = 'gm.userid IS NOT NULL' ;
if ( $useviewallgroups ) {
$viewallgroupsusers = get_users_by_capability ( $context , 'moodle/site:accessallgroups' , 'u.id, u.id' , '' , '' , '' , '' , $exceptions );
if ( ! empty ( $viewallgroupsusers )) {
$grouptest .= ' OR u.id IN (' . implode ( ',' , array_keys ( $viewallgroupsusers )) . ')' ;
}
}
$wherecond [] = " ( $grouptest ) " ;
}
2020-04-14 22:29:17 +01:00
// User exceptions.
2020-04-14 17:06:13 +01:00
if ( ! empty ( $exceptions )) {
$exceptions = ( array ) $exceptions ;
list ( $exsql , $exparams ) = $DB -> get_in_or_equal ( $exceptions , SQL_PARAMS_NAMED , 'exc' , false );
$params = array_merge ( $params , $exparams );
$wherecond [] = " u.id $exsql " ;
}
2020-04-14 22:29:17 +01:00
// Collect WHERE conditions and needed joins.
2011-10-14 12:48:00 +02:00
$where = implode ( ' AND ' , $wherecond );
if ( $where !== '' ) {
$where = 'WHERE ' . $where ;
}
$joins = implode ( " \n " , $joins );
2006-09-17 16:06:25 +00:00
2020-04-14 22:29:17 +01:00
// Finally! we have all the bits, run the query.
2011-10-14 12:48:00 +02:00
$sql = " SELECT $fields
FROM { user } u
$joins
$where
ORDER BY $sort " ;
2006-09-17 16:06:25 +00:00
2011-10-14 12:48:00 +02:00
return $DB -> get_records_sql ( $sql , $params , $limitfrom , $limitnum );
}
2006-09-20 02:19:08 +00:00
2011-10-14 12:48:00 +02:00
/**
* Re - sort a users array based on a sorting policy
*
* Will re - sort a $users results array ( from get_users_by_capability (), usually )
* based on a sorting policy . This is to support the odd practice of
* sorting teachers by 'authority' , where authority was " lowest id of the role
* assignment " .
*
* Will execute 1 database query . Only suitable for small numbers of users , as it
* uses an u . id IN () clause .
*
* Notes about the sorting criteria .
*
* As a default , we cannot rely on role . sortorder because then
* admins / coursecreators will always win . That is why the sane
* rule " is locality matters most " , with sortorder as 2 nd
* consideration .
*
* If you want role . sortorder , use the 'sortorder' policy , and
* name explicitly what roles you want to cover . It ' s probably
* a good idea to see what roles have the capabilities you want
* ( array_diff () them against roiles that have 'can-do-anything'
* to weed out admin - ish roles . Or fetch a list of roles from
* variables like $CFG -> coursecontact .
*
* @ param array $users Users array , keyed on userid
* @ param context $context
* @ param array $roles ids of the roles to include , optional
* @ param string $sortpolicy defaults to locality , more about
* @ return array sorted copy of the array
*/
function sort_by_roleassignment_authority ( $users , context $context , $roles = array (), $sortpolicy = 'locality' ) {
global $DB ;
2006-09-20 02:19:08 +00:00
2011-10-14 12:48:00 +02:00
$userswhere = ' ra.userid IN (' . implode ( ',' , array_keys ( $users )) . ')' ;
$contextwhere = 'AND ra.contextid IN (' . str_replace ( '/' , ',' , substr ( $context -> path , 1 )) . ')' ;
if ( empty ( $roles )) {
$roleswhere = '' ;
2010-09-17 07:37:51 +00:00
} else {
2011-10-14 12:48:00 +02:00
$roleswhere = ' AND ra.roleid IN (' . implode ( ',' , $roles ) . ')' ;
2010-03-31 07:41:31 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$sql = " SELECT ra.userid
FROM { role_assignments } ra
JOIN { role } r
ON ra . roleid = r . id
JOIN { context } ctx
ON ra . contextid = ctx . id
WHERE $userswhere
$contextwhere
$roleswhere " ;
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2011-10-14 12:48:00 +02:00
// Default 'locality' policy -- read PHPDoc notes
// about sort policies...
$orderby = 'ORDER BY '
. 'ctx.depth DESC, ' /* locality wins */
. 'r.sortorder ASC, ' /* rolesorting 2nd criteria */
. 'ra.id' ; /* role assignment order tie-breaker */
if ( $sortpolicy === 'sortorder' ) {
$orderby = 'ORDER BY '
. 'r.sortorder ASC, ' /* rolesorting 2nd criteria */
. 'ra.id' ; /* role assignment order tie-breaker */
2010-03-31 07:41:31 +00:00
}
2007-09-19 07:11:42 +00:00
2011-10-14 12:48:00 +02:00
$sortedids = $DB -> get_fieldset_sql ( $sql . $orderby );
$sortedusers = array ();
$seen = array ();
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
foreach ( $sortedids as $id ) {
// Avoid duplicates
if ( isset ( $seen [ $id ])) {
continue ;
}
$seen [ $id ] = true ;
2006-09-17 16:06:25 +00:00
2011-10-14 12:48:00 +02:00
// assign
$sortedusers [ $id ] = $users [ $id ];
}
return $sortedusers ;
2010-03-31 07:41:31 +00:00
}
/**
2011-10-14 12:48:00 +02:00
* Gets all the users assigned this role in this context or higher
*
2014-11-24 10:46:04 +08:00
* Note that moodle is based on capabilities and it is usually better
* to check permissions than to check role ids as the capabilities
* system is more flexible . If you really need , you can to use this
* function but consider has_capability () as a possible substitute .
*
2016-03-04 15:43:36 +02:00
* All $sort fields are added into $fields if not present there yet .
2014-11-24 10:46:04 +08:00
*
* If $roleid is an array or is empty ( all roles ) you need to set $fields
* ( and $sort by extension ) params according to it , as the first field
* returned by the database should be unique ( ra . id is the best candidate ) .
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid ( can also be an array of ints ! )
* @ param context $context
* @ param bool $parent if true , get list of users assigned in higher context too
* @ param string $fields fields from user ( u . ) , role assignment ( ra ) or role ( r . )
2012-08-08 13:56:12 +01:00
* @ param string $sort sort from user ( u . ) , role assignment ( ra . ) or role ( r . ) .
* null => use default sort from users_order_by_sql .
2012-12-06 15:26:43 +01:00
* @ param bool $all true means all , false means limit to enrolled users
2011-10-14 12:48:00 +02:00
* @ param string $group defaults to ''
* @ param mixed $limitfrom defaults to ''
* @ param mixed $limitnum defaults to ''
* @ param string $extrawheretest defaults to ''
2012-08-08 13:56:12 +01:00
* @ param array $whereorsortparams any paramter values used by $sort or $extrawheretest .
2011-10-14 12:48:00 +02:00
* @ return array
2010-03-31 07:41:31 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_role_users ( $roleid , context $context , $parent = false , $fields = '' ,
2012-12-06 15:26:43 +01:00
$sort = null , $all = true , $group = '' ,
2012-08-08 13:56:12 +01:00
$limitfrom = '' , $limitnum = '' , $extrawheretest = '' , $whereorsortparams = array ()) {
2010-03-31 07:41:31 +00:00
global $DB ;
2011-10-14 12:48:00 +02:00
if ( empty ( $fields )) {
2021-03-15 15:36:32 +00:00
$userfieldsapi = \core_user\fields :: for_name ();
2020-10-12 17:51:20 +01:00
$allnames = $userfieldsapi -> get_sql ( 'u' , false , '' , '' , false ) -> selects ;
2013-04-24 10:12:42 +08:00
$fields = 'u.id, u.confirmed, u.username, ' . $allnames . ', ' .
2011-11-16 13:01:55 +08:00
'u.maildisplay, u.mailformat, u.maildigest, u.email, u.emailstop, u.city, ' .
2011-10-14 12:48:00 +02:00
'u.country, u.picture, u.idnumber, u.department, u.institution, ' .
2012-05-18 11:40:35 +02:00
'u.lang, u.timezone, u.lastaccess, u.mnethostid, r.name AS rolename, r.sortorder, ' .
'r.shortname AS roleshortname, rn.name AS rolecoursealias' ;
2011-10-14 12:48:00 +02:00
}
2010-03-31 07:41:31 +00:00
2014-11-24 10:46:04 +08:00
// Prevent wrong function uses.
if (( empty ( $roleid ) || is_array ( $roleid )) && strpos ( $fields , 'ra.id' ) !== 0 ) {
debugging ( 'get_role_users() without specifying one single roleid needs to be called prefixing ' .
'role assignments id (ra.id) as unique field, you can use $fields param for it.' );
if ( ! empty ( $roleid )) {
// Solving partially the issue when specifying multiple roles.
$users = array ();
foreach ( $roleid as $id ) {
// Ignoring duplicated keys keeping the first user appearance.
$users = $users + get_role_users ( $id , $context , $parent , $fields , $sort , $all , $group ,
$limitfrom , $limitnum , $extrawheretest , $whereorsortparams );
}
return $users ;
}
}
2011-10-14 12:48:00 +02:00
$parentcontexts = '' ;
if ( $parent ) {
$parentcontexts = substr ( $context -> path , 1 ); // kill leading slash
$parentcontexts = str_replace ( '/' , ',' , $parentcontexts );
if ( $parentcontexts !== '' ) {
$parentcontexts = ' OR ra.contextid IN (' . $parentcontexts . ' )' ;
}
}
if ( $roleid ) {
2012-05-18 11:40:35 +02:00
list ( $rids , $params ) = $DB -> get_in_or_equal ( $roleid , SQL_PARAMS_NAMED , 'r' );
2011-10-14 12:48:00 +02:00
$roleselect = " AND ra.roleid $rids " ;
2010-03-31 07:41:31 +00:00
} else {
2011-10-14 12:48:00 +02:00
$params = array ();
$roleselect = '' ;
2006-09-17 16:06:25 +00:00
}
2012-05-18 11:40:35 +02:00
if ( $coursecontext = $context -> get_course_context ( false )) {
$params [ 'coursecontext' ] = $coursecontext -> id ;
} else {
$params [ 'coursecontext' ] = 0 ;
}
2011-10-14 12:48:00 +02:00
if ( $group ) {
$groupjoin = " JOIN { groups_members} gm ON gm.userid = u.id " ;
2012-05-18 11:40:35 +02:00
$groupselect = " AND gm.groupid = :groupid " ;
$params [ 'groupid' ] = $group ;
2011-10-14 12:48:00 +02:00
} else {
$groupjoin = '' ;
$groupselect = '' ;
}
2006-09-17 16:06:25 +00:00
2012-05-18 11:40:35 +02:00
$params [ 'contextid' ] = $context -> id ;
2010-04-05 07:34:50 +00:00
2011-10-14 12:48:00 +02:00
if ( $extrawheretest ) {
$extrawheretest = ' AND ' . $extrawheretest ;
2012-08-08 13:56:12 +01:00
}
if ( $whereorsortparams ) {
2012-12-06 15:26:43 +01:00
$params = array_merge ( $params , $whereorsortparams );
2011-10-14 12:48:00 +02:00
}
2012-08-08 13:56:12 +01:00
if ( ! $sort ) {
list ( $sort , $sortparams ) = users_order_by_sql ( 'u' );
$params = array_merge ( $params , $sortparams );
}
2016-03-04 15:43:36 +02:00
// Adding the fields from $sort that are not present in $fields.
$sortarray = preg_split ( '/,\s*/' , $sort );
$fieldsarray = preg_split ( '/,\s*/' , $fields );
2016-08-14 15:03:23 +03:00
// Discarding aliases from the fields.
$fieldnames = array ();
foreach ( $fieldsarray as $key => $field ) {
list ( $fieldnames [ $key ]) = explode ( ' ' , $field );
}
2016-03-04 15:43:36 +02:00
$addedfields = array ();
foreach ( $sortarray as $sortfield ) {
2016-03-16 10:42:52 +08:00
// Throw away any additional arguments to the sort (e.g. ASC/DESC).
2016-08-14 15:03:23 +03:00
list ( $sortfield ) = explode ( ' ' , $sortfield );
list ( $tableprefix ) = explode ( '.' , $sortfield );
$fieldpresent = false ;
foreach ( $fieldnames as $fieldname ) {
if ( $fieldname === $sortfield || $fieldname === $tableprefix . '.*' ) {
$fieldpresent = true ;
break ;
}
}
if ( ! $fieldpresent ) {
2016-03-04 15:43:36 +02:00
$fieldsarray [] = $sortfield ;
$addedfields [] = $sortfield ;
}
}
2016-08-14 15:03:23 +03:00
2016-03-04 15:43:36 +02:00
$fields = implode ( ', ' , $fieldsarray );
if ( ! empty ( $addedfields )) {
$addedfields = implode ( ', ' , $addedfields );
debugging ( 'get_role_users() adding ' . $addedfields . ' to the query result because they were required by $sort but missing in $fields' );
}
2012-12-06 15:26:43 +01:00
if ( $all === null ) {
// Previously null was used to indicate that parameter was not used.
$all = true ;
}
if ( ! $all and $coursecontext ) {
// Do not use get_enrolled_sql() here for performance reasons.
$ejoin = " JOIN { user_enrolments} ue ON ue.userid = u.id
JOIN { enrol } e ON ( e . id = ue . enrolid AND e . courseid = : ecourseid ) " ;
$params [ 'ecourseid' ] = $coursecontext -> instanceid ;
} else {
$ejoin = " " ;
}
2011-10-14 12:48:00 +02:00
$sql = " SELECT DISTINCT $fields , ra.roleid
FROM { role_assignments } ra
JOIN { user } u ON u . id = ra . userid
JOIN { role } r ON ra . roleid = r . id
2012-12-06 15:26:43 +01:00
$ejoin
2012-05-18 11:40:35 +02:00
LEFT JOIN { role_names } rn ON ( rn . contextid = : coursecontext AND rn . roleid = r . id )
2011-10-14 12:48:00 +02:00
$groupjoin
2012-05-18 11:40:35 +02:00
WHERE ( ra . contextid = : contextid $parentcontexts )
2011-10-14 12:48:00 +02:00
$roleselect
$groupselect
$extrawheretest
ORDER BY $sort " ; // join now so that we can just use fullname() later
2010-04-05 07:34:50 +00:00
2011-10-14 12:48:00 +02:00
return $DB -> get_records_sql ( $sql , $params , $limitfrom , $limitnum );
2010-04-05 07:34:50 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Counts all the users assigned this role in this context or higher
2009-05-19 07:50:54 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int | array $roleid either int or an array of ints
* @ param context $context
* @ param bool $parent if true , get list of users assigned in higher context too
* @ return int Returns the result count
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function count_role_users ( $roleid , context $context , $parent = false ) {
global $DB ;
2009-05-16 20:53:21 +00:00
2011-10-14 12:48:00 +02:00
if ( $parent ) {
if ( $contexts = $context -> get_parent_context_ids ()) {
$parentcontexts = ' OR r.contextid IN (' . implode ( ',' , $contexts ) . ')' ;
} else {
$parentcontexts = '' ;
2009-11-04 19:24:12 +00:00
}
2011-10-14 12:48:00 +02:00
} else {
$parentcontexts = '' ;
2006-08-08 05:13:06 +00:00
}
2009-06-19 14:25:56 +00:00
2011-10-14 12:48:00 +02:00
if ( $roleid ) {
list ( $rids , $params ) = $DB -> get_in_or_equal ( $roleid , SQL_PARAMS_QM );
$roleselect = " AND r.roleid $rids " ;
} else {
$params = array ();
$roleselect = '' ;
}
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
array_unshift ( $params , $context -> id );
2006-08-08 05:13:06 +00:00
2015-03-20 14:31:34 +00:00
$sql = " SELECT COUNT(DISTINCT u.id)
2011-10-14 12:48:00 +02:00
FROM { role_assignments } r
JOIN { user } u ON u . id = r . userid
WHERE ( r . contextid = ? $parentcontexts )
$roleselect
AND u . deleted = 0 " ;
return $DB -> count_records_sql ( $sql , $params );
2006-08-08 05:13:06 +00:00
}
2007-03-03 21:07:07 +00:00
/**
2021-09-27 08:19:38 +02:00
* This function gets the list of course and course category contexts that this user has a particular capability in .
2017-08-22 18:09:35 +01:00
*
* It is now reasonably efficient , but bear in mind that if there are users who have the capability
2021-09-27 08:19:38 +02:00
* everywhere , it may return an array of all contexts .
2011-10-14 12:48:00 +02:00
*
* @ param string $capability Capability in question
* @ param int $userid User ID or null for current user
2021-09-27 08:19:38 +02:00
* @ param bool $getcategories Wether to return also course_categories
2011-10-14 12:48:00 +02:00
* @ param bool $doanything True if 'doanything' is permitted ( default )
2021-09-27 08:19:38 +02:00
* @ param string $coursefieldsexceptid Leave blank if you only need 'id' in the course records ;
2017-02-09 09:20:38 +08:00
* otherwise use a comma - separated list of the fields you require , not including id .
* Add ctxid , ctxpath , ctxdepth etc to return course context information for preloading .
2021-09-27 08:19:38 +02:00
* @ param string $categoryfieldsexceptid Leave blank if you only need 'id' in the course records ;
* otherwise use a comma - separated list of the fields you require , not including id .
* Add ctxid , ctxpath , ctxdepth etc to return course context information for preloading .
* @ param string $courseorderby If set , use a comma - separated list of fields from course
* table with sql modifiers ( DESC ) if needed
* @ param string $categoryorderby If set , use a comma - separated list of fields from course_category
2011-10-14 12:48:00 +02:00
* table with sql modifiers ( DESC ) if needed
2017-02-09 09:20:38 +08:00
* @ param int $limit Limit the number of courses to return on success . Zero equals all entries .
2021-09-27 08:19:38 +02:00
* @ return array Array of categories and courses .
2007-03-03 21:07:07 +00:00
*/
2021-09-27 08:19:38 +02:00
function get_user_capability_contexts ( string $capability , bool $getcategories , $userid = null , $doanything = true ,
$coursefieldsexceptid = '' , $categoryfieldsexceptid = '' , $courseorderby = '' ,
$categoryorderby = '' , $limit = 0 ) : array {
2017-08-22 18:09:35 +01:00
global $DB , $USER ;
// Default to current user.
if ( ! $userid ) {
$userid = $USER -> id ;
}
2022-04-22 14:27:44 +02:00
if ( ! $capinfo = get_capability_info ( $capability )) {
debugging ( 'Capability "' . $capability . '" was not found! This has to be fixed in code.' );
return [ false , false ];
}
2017-08-22 18:09:35 +01:00
if ( $doanything && is_siteadmin ( $userid )) {
// If the user is a site admin and $doanything is enabled then there is no need to restrict
// the list of courses.
$contextlimitsql = '' ;
$contextlimitparams = [];
} else {
// Gets SQL to limit contexts ('x' table) to those where the user has this capability.
list ( $contextlimitsql , $contextlimitparams ) = \core\access\get_user_capability_course_helper :: get_sql (
2022-04-22 14:27:44 +02:00
$userid , $capinfo -> name );
2017-08-22 18:09:35 +01:00
if ( ! $contextlimitsql ) {
// If the does not have this capability in any context, return false without querying.
2021-09-27 08:19:38 +02:00
return [ false , false ];
2017-08-22 18:09:35 +01:00
}
$contextlimitsql = 'WHERE' . $contextlimitsql ;
}
2010-03-31 07:41:31 +00:00
2021-09-27 08:19:38 +02:00
$categories = [];
if ( $getcategories ) {
$fieldlist = \core\access\get_user_capability_course_helper :: map_fieldnames ( $categoryfieldsexceptid );
if ( $categoryorderby ) {
$fields = explode ( ',' , $categoryorderby );
2023-04-18 10:23:01 +01:00
$categoryorderby = '' ;
2021-09-27 08:19:38 +02:00
foreach ( $fields as $field ) {
2023-04-18 10:23:01 +01:00
if ( $categoryorderby ) {
$categoryorderby .= ',' ;
2017-08-22 18:09:35 +01:00
}
2023-04-18 10:23:01 +01:00
$categoryorderby .= 'c.' . $field ;
2021-09-27 08:19:38 +02:00
}
2023-04-18 10:23:01 +01:00
$categoryorderby = 'ORDER BY ' . $categoryorderby ;
2021-09-27 08:19:38 +02:00
}
$rs = $DB -> get_recordset_sql ( "
SELECT c . id $fieldlist
FROM { course_categories } c
JOIN { context } x ON c . id = x . instanceid AND x . contextlevel = ?
$contextlimitsql
2023-04-18 10:23:01 +01:00
$categoryorderby " , array_merge([CONTEXT_COURSECAT], $contextlimitparams ));
2021-09-27 08:19:38 +02:00
$basedlimit = $limit ;
foreach ( $rs as $category ) {
$categories [] = $category ;
$basedlimit -- ;
if ( $basedlimit == 0 ) {
break ;
2017-02-09 09:20:38 +08:00
}
2007-03-03 21:07:07 +00:00
}
2023-04-18 10:23:01 +01:00
$rs -> close ();
2007-03-03 21:07:07 +00:00
}
2021-09-27 08:19:38 +02:00
$courses = [];
$fieldlist = \core\access\get_user_capability_course_helper :: map_fieldnames ( $coursefieldsexceptid );
if ( $courseorderby ) {
$fields = explode ( ',' , $courseorderby );
$courseorderby = '' ;
2020-05-06 09:14:49 +01:00
foreach ( $fields as $field ) {
2021-09-27 08:19:38 +02:00
if ( $courseorderby ) {
$courseorderby .= ',' ;
2010-05-21 11:43:37 +00:00
}
2021-09-27 08:19:38 +02:00
$courseorderby .= 'c.' . $field ;
2007-03-03 21:07:07 +00:00
}
2021-09-27 08:19:38 +02:00
$courseorderby = 'ORDER BY ' . $courseorderby ;
2007-03-03 21:07:07 +00:00
}
2017-08-22 18:09:35 +01:00
$rs = $DB -> get_recordset_sql ( "
SELECT c . id $fieldlist
FROM { course } c
2021-09-27 08:19:38 +02:00
JOIN { context } x ON c . id = x . instanceid AND x . contextlevel = ?
2017-08-22 18:09:35 +01:00
$contextlimitsql
2021-09-27 08:19:38 +02:00
$courseorderby " , array_merge([CONTEXT_COURSE], $contextlimitparams ));
2012-01-14 21:36:02 +01:00
foreach ( $rs as $course ) {
2017-08-22 18:09:35 +01:00
$courses [] = $course ;
$limit -- ;
if ( $limit == 0 ) {
break ;
2011-10-14 12:48:00 +02:00
}
}
$rs -> close ();
2021-09-27 08:19:38 +02:00
return [ $categories , $courses ];
}
/**
* This function gets the list of courses that this user has a particular capability in .
*
* It is now reasonably efficient , but bear in mind that if there are users who have the capability
* everywhere , it may return an array of all courses .
*
* @ param string $capability Capability in question
* @ param int $userid User ID or null for current user
* @ param bool $doanything True if 'doanything' is permitted ( default )
* @ param string $fieldsexceptid Leave blank if you only need 'id' in the course records ;
* otherwise use a comma - separated list of the fields you require , not including id .
* Add ctxid , ctxpath , ctxdepth etc to return course context information for preloading .
* @ param string $orderby If set , use a comma - separated list of fields from course
* table with sql modifiers ( DESC ) if needed
* @ param int $limit Limit the number of courses to return on success . Zero equals all entries .
* @ return array | bool Array of courses , if none found false is returned .
*/
function get_user_capability_course ( $capability , $userid = null , $doanything = true , $fieldsexceptid = '' ,
$orderby = '' , $limit = 0 ) {
list ( $categories , $courses ) = get_user_capability_contexts (
$capability ,
false ,
$userid ,
$doanything ,
$fieldsexceptid ,
'' ,
$orderby ,
'' ,
$limit
);
return $courses ;
2007-03-03 21:07:07 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Switches the current user to another role for the current session and only
* in the given context .
2006-08-08 05:13:06 +00:00
*
2011-10-14 12:48:00 +02:00
* The caller * must * check
* - that this op is allowed
* - that the requested role can be switched to in this context ( use get_switchable_roles )
* - that the requested role is NOT $CFG -> defaultuserroleid
2006-08-08 05:13:06 +00:00
*
2011-10-14 12:48:00 +02:00
* To " unswitch " pass 0 as the roleid .
*
* This function * will * modify $USER -> access - beware
*
* @ param integer $roleid the role to switch to .
* @ param context $context the context in which to perform the switch .
* @ return bool success or failure .
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_switch ( $roleid , context $context ) {
global $USER ;
2006-09-20 21:00:45 +00:00
2016-05-14 21:14:31 +09:30
// Add the ghost RA to $USER->access as $USER->access['rsw'][$path] = $roleid.
// To un-switch just unset($USER->access['rsw'][$path]).
2011-10-14 12:48:00 +02:00
//
// Note: it is not possible to switch to roles that do not have course:view
2006-09-20 21:00:45 +00:00
2012-01-15 00:14:44 +01:00
if ( ! isset ( $USER -> access )) {
load_all_capabilities ();
2011-10-14 12:48:00 +02:00
}
2007-09-13 13:44:35 +00:00
2023-02-28 13:46:22 +01:00
// Make sure that course index is refreshed.
if ( $coursecontext = $context -> get_course_context ()) {
core_courseformat\base :: session_cache_reset ( get_course ( $coursecontext -> instanceid ));
}
2012-01-15 00:14:44 +01:00
// Add the switch RA
2011-10-14 12:48:00 +02:00
if ( $roleid == 0 ) {
unset ( $USER -> access [ 'rsw' ][ $context -> path ]);
return true ;
2006-08-08 05:13:06 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$USER -> access [ 'rsw' ][ $context -> path ] = $roleid ;
2006-08-08 05:13:06 +00:00
return true ;
}
2011-10-14 12:48:00 +02:00
/**
* Checks if the user has switched roles within the given course .
*
2012-01-14 19:12:43 +01:00
* Note : You can only switch roles within the course , hence it takes a course id
2011-10-14 12:48:00 +02:00
* rather than a context . On that note Petr volunteered to implement this across
* all other contexts , all requests for this should be forwarded to him ;)
*
* @ param int $courseid The id of the course to check
* @ return bool True if the user has switched roles within the course .
*/
function is_role_switched ( $courseid ) {
global $USER ;
$context = context_course :: instance ( $courseid , MUST_EXIST );
return ( ! empty ( $USER -> access [ 'rsw' ][ $context -> path ]));
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Get any role that has an override on exact context
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param context $context The context to check
* @ return array An array of roles
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_roles_with_override_on_context ( context $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
return $DB -> get_records_sql ( " SELECT r.*
FROM { role_capabilities } rc , { role } r
WHERE rc . roleid = r . id AND rc . contextid = ? " ,
array ( $context -> id ));
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Get all capabilities for this role on this context ( overrides )
*
* @ param stdClass $role
* @ param context $context
* @ return array
*/
function get_capabilities_from_role_on_context ( $role , context $context ) {
global $DB ;
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
return $DB -> get_records_sql ( " SELECT *
FROM { role_capabilities }
WHERE contextid = ? AND roleid = ? " ,
array ( $context -> id , $role -> id ));
2006-08-08 05:13:06 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Find all user assignment of users for this role , on this context
*
* @ param stdClass $role
* @ param context $context
* @ return array
*/
function get_users_from_role_on_context ( $role , context $context ) {
global $DB ;
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
return $DB -> get_records_sql ( " SELECT *
FROM { role_assignments }
WHERE contextid = ? AND roleid = ? " ,
array ( $context -> id , $role -> id ));
}
2006-08-08 05:13:06 +00:00
2008-11-21 06:19:52 +00:00
/**
2011-10-14 12:48:00 +02:00
* Simple function returning a boolean true if user has roles
* in context or parent contexts , otherwise false .
*
* @ param int $userid
* @ param int $roleid
* @ param int $contextid empty means any context
* @ return bool
2008-11-21 06:19:52 +00:00
*/
2011-10-14 12:48:00 +02:00
function user_has_role_assignment ( $userid , $roleid , $contextid = 0 ) {
global $DB ;
if ( $contextid ) {
if ( ! $context = context :: instance_by_id ( $contextid , IGNORE_MISSING )) {
return false ;
}
$parents = $context -> get_parent_context_ids ( true );
list ( $contexts , $params ) = $DB -> get_in_or_equal ( $parents , SQL_PARAMS_NAMED , 'r' );
$params [ 'userid' ] = $userid ;
$params [ 'roleid' ] = $roleid ;
$sql = " SELECT COUNT(ra.id)
FROM { role_assignments } ra
WHERE ra . userid = : userid AND ra . roleid = : roleid AND ra . contextid $contexts " ;
$count = $DB -> get_field_sql ( $sql , $params );
return ( $count > 0 );
} else {
return $DB -> record_exists ( 'role_assignments' , array ( 'userid' => $userid , 'roleid' => $roleid ));
2008-11-21 06:19:52 +00:00
}
}
2006-08-08 05:13:06 +00:00
/**
2013-04-07 17:39:29 +02:00
* Get localised role name or alias if exists and format the text .
2008-10-30 06:26:18 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param stdClass $role role object
2012-05-18 11:40:35 +02:00
* - optional 'coursealias' property should be included for performance reasons if course context used
* - description property is not required here
* @ param context | bool $context empty means system context
* @ param int $rolenamedisplay type of role name
* @ return string localised role name or course role name alias
2006-08-08 05:13:06 +00:00
*/
2012-05-18 11:40:35 +02:00
function role_get_name ( stdClass $role , $context = null , $rolenamedisplay = ROLENAME_ALIAS ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-08-13 15:48:57 +00:00
2012-05-18 11:40:35 +02:00
if ( $rolenamedisplay == ROLENAME_SHORT ) {
return $role -> shortname ;
}
if ( ! $context or ! $coursecontext = $context -> get_course_context ( false )) {
$coursecontext = null ;
}
if ( $coursecontext and ! property_exists ( $role , 'coursealias' ) and ( $rolenamedisplay == ROLENAME_ALIAS or $rolenamedisplay == ROLENAME_BOTH or $rolenamedisplay == ROLENAME_ALIAS_RAW )) {
$role = clone ( $role ); // Do not modify parameters.
if ( $r = $DB -> get_record ( 'role_names' , array ( 'roleid' => $role -> id , 'contextid' => $coursecontext -> id ))) {
$role -> coursealias = $r -> name ;
} else {
$role -> coursealias = null ;
}
}
if ( $rolenamedisplay == ROLENAME_ALIAS_RAW ) {
if ( $coursecontext ) {
return $role -> coursealias ;
} else {
return null ;
}
}
if ( trim ( $role -> name ) !== '' ) {
// For filtering always use context where was the thing defined - system for roles here.
$original = format_string ( $role -> name , true , array ( 'context' => context_system :: instance ()));
2011-10-14 12:48:00 +02:00
} else {
2012-05-18 11:40:35 +02:00
// Empty role->name means we want to see localised role name based on shortname,
// only default roles are supposed to be localised.
switch ( $role -> shortname ) {
case 'manager' : $original = get_string ( 'manager' , 'role' ); break ;
case 'coursecreator' : $original = get_string ( 'coursecreators' ); break ;
case 'editingteacher' : $original = get_string ( 'defaultcourseteacher' ); break ;
case 'teacher' : $original = get_string ( 'noneditingteacher' ); break ;
case 'student' : $original = get_string ( 'defaultcoursestudent' ); break ;
case 'guest' : $original = get_string ( 'guest' ); break ;
case 'user' : $original = get_string ( 'authenticateduser' ); break ;
case 'frontpage' : $original = get_string ( 'frontpageuser' , 'role' ); break ;
// We should not get here, the role UI should require the name for custom roles!
default : $original = $role -> shortname ; break ;
}
}
if ( $rolenamedisplay == ROLENAME_ORIGINAL ) {
return $original ;
}
if ( $rolenamedisplay == ROLENAME_ORIGINALANDSHORT ) {
return " $original ( $role->shortname ) " ;
}
if ( $rolenamedisplay == ROLENAME_ALIAS ) {
2023-01-06 22:29:49 +08:00
if ( $coursecontext && $role -> coursealias && trim ( $role -> coursealias ) !== '' ) {
2012-05-18 11:40:35 +02:00
return format_string ( $role -> coursealias , true , array ( 'context' => $coursecontext ));
} else {
return $original ;
}
}
if ( $rolenamedisplay == ROLENAME_BOTH ) {
2023-01-06 22:29:49 +08:00
if ( $coursecontext && $role -> coursealias && trim ( $role -> coursealias ) !== '' ) {
2012-05-18 11:40:35 +02:00
return format_string ( $role -> coursealias , true , array ( 'context' => $coursecontext )) . " ( $original ) " ;
} else {
return $original ;
}
}
throw new coding_exception ( 'Invalid $rolenamedisplay parameter specified in role_get_name()' );
}
/**
* Returns localised role description if available .
* If the name is empty it tries to find the default role name using
* hardcoded list of default role names or other methods in the future .
*
* @ param stdClass $role
* @ return string localised role name
*/
function role_get_description ( stdClass $role ) {
if ( ! html_is_blank ( $role -> description )) {
return format_text ( $role -> description , FORMAT_HTML , array ( 'context' => context_system :: instance ()));
}
switch ( $role -> shortname ) {
case 'manager' : return get_string ( 'managerdescription' , 'role' );
case 'coursecreator' : return get_string ( 'coursecreatorsdescription' );
case 'editingteacher' : return get_string ( 'defaultcourseteacherdescription' );
case 'teacher' : return get_string ( 'noneditingteacherdescription' );
case 'student' : return get_string ( 'defaultcoursestudentdescription' );
case 'guest' : return get_string ( 'guestdescription' );
case 'user' : return get_string ( 'authenticateduserdescription' );
case 'frontpage' : return get_string ( 'frontpageuserdescription' , 'role' );
default : return '' ;
2011-10-14 12:48:00 +02:00
}
}
2006-08-08 05:13:06 +00:00
2012-07-06 12:20:01 +01:00
/**
* Get all the localised role names for a context .
2013-03-17 20:15:59 +01:00
*
2013-04-07 17:39:29 +02:00
* In new installs default roles have empty names , this function
* add localised role names using current language pack .
*
2013-03-17 20:15:59 +01:00
* @ param context $context the context , null means system context
2012-07-06 12:20:01 +01:00
* @ param array of role objects with a -> localname field containing the context - specific role name .
2013-03-17 20:15:59 +01:00
* @ param int $rolenamedisplay
* @ param bool $returnmenu true means id => localname , false means id => rolerecord
* @ return array Array of context - specific role names , or role objects with a -> localname field added .
2012-07-06 12:20:01 +01:00
*/
2013-03-17 20:15:59 +01:00
function role_get_names ( context $context = null , $rolenamedisplay = ROLENAME_ALIAS , $returnmenu = null ) {
return role_fix_names ( get_all_roles ( $context ), $context , $rolenamedisplay , $returnmenu );
2012-07-06 12:20:01 +01:00
}
2011-10-14 12:48:00 +02:00
/**
2013-04-07 17:39:29 +02:00
* Prepare list of roles for display , apply aliases and localise default role names .
2011-10-14 12:48:00 +02:00
*
2012-05-18 11:40:35 +02:00
* @ param array $roleoptions array roleid => roleobject ( with optional coursealias ), strings are accepted for backwards compatibility only
2013-03-17 20:15:59 +01:00
* @ param context $context the context , null means system context
2011-10-14 12:48:00 +02:00
* @ param int $rolenamedisplay
2012-05-18 11:40:35 +02:00
* @ param bool $returnmenu null means keep the same format as $roleoptions , true means id => localname , false means id => rolerecord
2012-01-14 19:12:43 +01:00
* @ return array Array of context - specific role names , or role objects with a -> localname field added .
2011-10-14 12:48:00 +02:00
*/
2013-03-17 20:15:59 +01:00
function role_fix_names ( $roleoptions , context $context = null , $rolenamedisplay = ROLENAME_ALIAS , $returnmenu = null ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2006-08-13 15:48:57 +00:00
2012-05-18 11:40:35 +02:00
if ( empty ( $roleoptions )) {
return array ();
}
2006-08-08 05:13:06 +00:00
2012-05-18 11:40:35 +02:00
if ( ! $context or ! $coursecontext = $context -> get_course_context ( false )) {
$coursecontext = null ;
}
// We usually need all role columns...
$first = reset ( $roleoptions );
if ( $returnmenu === null ) {
$returnmenu = ! is_object ( $first );
}
if ( ! is_object ( $first ) or ! property_exists ( $first , 'shortname' )) {
$allroles = get_all_roles ( $context );
foreach ( $roleoptions as $rid => $unused ) {
$roleoptions [ $rid ] = $allroles [ $rid ];
2011-10-14 12:48:00 +02:00
}
}
2006-08-08 05:13:06 +00:00
2012-05-18 11:40:35 +02:00
// Inject coursealias if necessary.
if ( $coursecontext and ( $rolenamedisplay == ROLENAME_ALIAS_RAW or $rolenamedisplay == ROLENAME_ALIAS or $rolenamedisplay == ROLENAME_BOTH )) {
$first = reset ( $roleoptions );
if ( ! property_exists ( $first , 'coursealias' )) {
$aliasnames = $DB -> get_records ( 'role_names' , array ( 'contextid' => $coursecontext -> id ));
foreach ( $aliasnames as $alias ) {
if ( isset ( $roleoptions [ $alias -> roleid ])) {
$roleoptions [ $alias -> roleid ] -> coursealias = $alias -> name ;
2006-08-09 04:51:05 +00:00
}
}
2011-10-14 12:48:00 +02:00
}
2006-08-13 15:48:57 +00:00
}
2008-10-30 06:26:18 +00:00
2012-05-18 11:40:35 +02:00
// Add localname property.
foreach ( $roleoptions as $rid => $role ) {
$roleoptions [ $rid ] -> localname = role_get_name ( $role , $coursecontext , $rolenamedisplay );
}
if ( ! $returnmenu ) {
return $roleoptions ;
2011-10-14 12:48:00 +02:00
}
2012-05-18 11:40:35 +02:00
$menu = array ();
foreach ( $roleoptions as $rid => $role ) {
$menu [ $rid ] = $role -> localname ;
}
return $menu ;
2006-08-08 05:13:06 +00:00
}
2008-10-30 06:26:18 +00:00
/**
2011-10-14 12:48:00 +02:00
* Aids in detecting if a new line is required when reading a new capability
2008-10-30 06:26:18 +00:00
*
2011-10-14 12:48:00 +02:00
* This function helps admin / roles / manage . php etc to detect if a new line should be printed
* when we read in a new capability .
* Most of the time , if the 2 components are different we should print a new line , ( e . g . course system -> rss client )
* but when we are in grade , all reports / import / export capabilities should be together
*
* @ param string $cap component string a
* @ param string $comp component string b
* @ param int $contextlevel
* @ return bool whether 2 component are in different " sections "
*/
function component_level_changed ( $cap , $comp , $contextlevel ) {
2008-10-30 06:26:18 +00:00
2011-10-14 12:48:00 +02:00
if ( strstr ( $cap -> component , '/' ) && strstr ( $comp , '/' )) {
$compsa = explode ( '/' , $cap -> component );
$compsb = explode ( '/' , $comp );
2008-10-30 06:26:18 +00:00
2011-10-14 12:48:00 +02:00
// list of system reports
if (( $compsa [ 0 ] == 'report' ) && ( $compsb [ 0 ] == 'report' )) {
return false ;
}
2008-10-30 06:26:18 +00:00
2011-10-14 12:48:00 +02:00
// we are in gradebook, still
if (( $compsa [ 0 ] == 'gradeexport' || $compsa [ 0 ] == 'gradeimport' || $compsa [ 0 ] == 'gradereport' ) &&
( $compsb [ 0 ] == 'gradeexport' || $compsb [ 0 ] == 'gradeimport' || $compsb [ 0 ] == 'gradereport' )) {
return false ;
}
2008-10-30 06:26:18 +00:00
2011-10-14 12:48:00 +02:00
if (( $compsa [ 0 ] == 'coursereport' ) && ( $compsb [ 0 ] == 'coursereport' )) {
return false ;
}
2008-10-30 06:26:18 +00:00
}
2011-10-14 12:48:00 +02:00
return ( $cap -> component != $comp || $cap -> contextlevel != $contextlevel );
2008-10-30 06:26:18 +00:00
}
2006-08-08 05:13:06 +00:00
2008-11-05 08:17:30 +00:00
/**
2011-10-14 12:48:00 +02:00
* Fix the roles . sortorder field in the database , so it contains sequential integers ,
* and return an array of roleids in order .
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param array $allroles array of roles , as returned by get_all_roles ();
* @ return array $role -> sortorder =-> $role -> id with the keys in ascending order .
2008-11-05 08:17:30 +00:00
*/
2011-10-14 12:48:00 +02:00
function fix_role_sortorder ( $allroles ) {
global $DB ;
$rolesort = array ();
$i = 0 ;
foreach ( $allroles as $role ) {
$rolesort [ $i ] = $role -> id ;
if ( $role -> sortorder != $i ) {
$r = new stdClass ();
$r -> id = $role -> id ;
$r -> sortorder = $i ;
$DB -> update_record ( 'role' , $r );
$allroles [ $role -> id ] -> sortorder = $i ;
}
$i ++ ;
}
return $rolesort ;
2008-11-05 08:17:30 +00:00
}
/**
2011-10-14 12:48:00 +02:00
* Switch the sort order of two roles ( used in admin / roles / manage . php ) .
2009-05-19 07:50:54 +00:00
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $first The first role . Actually , only -> sortorder is used .
* @ param stdClass $second The second role . Actually , only -> sortorder is used .
2011-10-14 12:48:00 +02:00
* @ return boolean success or failure
2008-11-05 08:17:30 +00:00
*/
2011-10-14 12:48:00 +02:00
function switch_roles ( $first , $second ) {
global $DB ;
$temp = $DB -> get_field ( 'role' , 'MAX(sortorder) + 1' , array ());
$result = $DB -> set_field ( 'role' , 'sortorder' , $temp , array ( 'sortorder' => $first -> sortorder ));
$result = $result && $DB -> set_field ( 'role' , 'sortorder' , $first -> sortorder , array ( 'sortorder' => $second -> sortorder ));
$result = $result && $DB -> set_field ( 'role' , 'sortorder' , $second -> sortorder , array ( 'sortorder' => $temp ));
return $result ;
2008-11-05 08:17:30 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Duplicates all the base definitions of a role
2009-05-19 07:50:54 +00:00
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $sourcerole role to copy from
2011-10-14 12:48:00 +02:00
* @ param int $targetrole id of role to copy to
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_cap_duplicate ( $sourcerole , $targetrole ) {
global $DB ;
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
$systemcontext = context_system :: instance ();
$caps = $DB -> get_records_sql ( " SELECT *
FROM { role_capabilities }
WHERE roleid = ? AND contextid = ? " ,
array ( $sourcerole -> id , $systemcontext -> id ));
// adding capabilities
foreach ( $caps as $cap ) {
unset ( $cap -> id );
$cap -> roleid = $targetrole ;
$DB -> insert_record ( 'role_capabilities' , $cap );
2006-09-12 19:54:33 +00:00
}
2016-05-14 21:14:31 +09:30
// Reset any cache of this role, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $targetrole );
2006-09-20 08:30:49 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2011-10-14 12:48:00 +02:00
* Returns two lists , this can be used to find out if user has capability .
* Having any needed role and no forbidden role in this context means
* user has this capability in this context .
* Use get_role_names_with_cap_in_context () if you need role names to display in the UI
2009-05-22 02:03:55 +00:00
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $context
2011-10-14 12:48:00 +02:00
* @ param string $capability
* @ return array ( $neededroles , $forbiddenroles )
2006-08-08 05:13:06 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_roles_with_cap_in_context ( $context , $capability ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$sql = " SELECT rc.id, rc.roleid, rc.permission, ctx.depth
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
WHERE rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY rc . roleid ASC , ctx . depth DESC " ;
$params = array ( 'cap' => $capability );
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( ! $capdefs = $DB -> get_records_sql ( $sql , $params )) {
// no cap definitions --> no capability
return array ( array (), array ());
2006-08-28 08:42:30 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$forbidden = array ();
$needed = array ();
2020-05-06 09:14:49 +01:00
foreach ( $capdefs as $def ) {
2011-10-14 12:48:00 +02:00
if ( isset ( $forbidden [ $def -> roleid ])) {
continue ;
}
if ( $def -> permission == CAP_PROHIBIT ) {
$forbidden [ $def -> roleid ] = $def -> roleid ;
unset ( $needed [ $def -> roleid ]);
continue ;
}
if ( ! isset ( $needed [ $def -> roleid ])) {
if ( $def -> permission == CAP_ALLOW ) {
$needed [ $def -> roleid ] = true ;
} else if ( $def -> permission == CAP_PREVENT ) {
$needed [ $def -> roleid ] = false ;
2006-09-20 21:00:45 +00:00
}
2006-09-05 03:07:56 +00:00
}
2006-08-09 13:14:15 +00:00
}
2011-10-14 12:48:00 +02:00
unset ( $capdefs );
2007-01-11 06:06:11 +00:00
2011-10-14 12:48:00 +02:00
// remove all those roles not allowing
2020-05-06 09:14:49 +01:00
foreach ( $needed as $key => $value ) {
2011-10-14 12:48:00 +02:00
if ( ! $value ) {
unset ( $needed [ $key ]);
} else {
$needed [ $key ] = $key ;
}
2008-11-21 05:46:45 +00:00
}
2006-08-08 05:13:06 +00:00
2011-10-14 12:48:00 +02:00
return array ( $needed , $forbidden );
2006-08-08 05:13:06 +00:00
}
2008-05-12 15:28:34 +00:00
/**
2011-10-14 12:48:00 +02:00
* Returns an array of role IDs that have ALL of the the supplied capabilities
* Uses get_roles_with_cap_in_context () . Returns $allowed minus $forbidden
2008-05-12 15:28:34 +00:00
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $context
2011-10-14 12:48:00 +02:00
* @ param array $capabilities An array of capabilities
* @ return array of roles with all of the required capabilities
2008-05-12 15:28:34 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_roles_with_caps_in_context ( $context , $capabilities ) {
$neededarr = array ();
$forbiddenarr = array ();
2020-05-06 09:14:49 +01:00
foreach ( $capabilities as $caprequired ) {
2011-10-14 12:48:00 +02:00
list ( $neededarr [], $forbiddenarr []) = get_roles_with_cap_in_context ( $context , $caprequired );
2008-05-12 15:28:34 +00:00
}
2006-09-20 08:30:49 +00:00
2011-10-14 12:48:00 +02:00
$rolesthatcanrate = array ();
if ( ! empty ( $neededarr )) {
foreach ( $neededarr as $needed ) {
if ( empty ( $rolesthatcanrate )) {
$rolesthatcanrate = $needed ;
} else {
//only want roles that have all caps
$rolesthatcanrate = array_intersect_key ( $rolesthatcanrate , $needed );
}
}
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
if ( ! empty ( $forbiddenarr ) && ! empty ( $rolesthatcanrate )) {
foreach ( $forbiddenarr as $forbidden ) {
//remove any roles that are forbidden any of the caps
$rolesthatcanrate = array_diff ( $rolesthatcanrate , $forbidden );
}
}
return $rolesthatcanrate ;
2010-03-31 07:41:31 +00:00
}
/**
2011-10-14 12:48:00 +02:00
* Returns an array of role names that have ALL of the the supplied capabilities
* Uses get_roles_with_caps_in_context () . Returns $allowed minus $forbidden
*
2012-01-14 19:12:43 +01:00
* @ param stdClass $context
2011-10-14 12:48:00 +02:00
* @ param array $capabilities An array of capabilities
* @ return array of roles with all of the required capabilities
2010-03-31 07:41:31 +00:00
*/
2011-10-14 12:48:00 +02:00
function get_role_names_with_caps_in_context ( $context , $capabilities ) {
global $DB ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
$rolesthatcanrate = get_roles_with_caps_in_context ( $context , $capabilities );
2012-05-18 11:40:35 +02:00
$allroles = $DB -> get_records ( 'role' , null , 'sortorder DESC' );
2010-03-31 07:41:31 +00:00
2012-05-18 11:40:35 +02:00
$roles = array ();
2011-10-14 12:48:00 +02:00
foreach ( $rolesthatcanrate as $r ) {
2012-05-18 11:40:35 +02:00
$roles [ $r ] = $allroles [ $r ];
2011-10-14 12:48:00 +02:00
}
2012-05-18 11:40:35 +02:00
return role_fix_names ( $roles , $context , ROLENAME_ALIAS , true );
2010-03-31 07:41:31 +00:00
}
2008-11-11 07:23:25 +00:00
/**
2011-10-14 12:48:00 +02:00
* This function verifies the prohibit comes from this context
* and there are no more prohibits in parent contexts .
2009-05-22 02:03:55 +00:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid
* @ param context $context
* @ param string $capability name
2009-11-01 11:31:16 +00:00
* @ return bool
2008-11-11 07:23:25 +00:00
*/
2011-10-14 12:48:00 +02:00
function prohibit_is_removable ( $roleid , context $context , $capability ) {
global $DB ;
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
$params = array ( 'roleid' => $roleid , 'cap' => $capability , 'prohibit' => CAP_PROHIBIT );
$sql = " SELECT ctx.id
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
WHERE rc . roleid = : roleid AND rc . permission = : prohibit AND rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY ctx . depth DESC " ;
if ( ! $prohibits = $DB -> get_records_sql ( $sql , $params )) {
// no prohibits == nothing to remove
return true ;
}
if ( count ( $prohibits ) > 1 ) {
2012-01-14 19:12:43 +01:00
// more prohibits can not be removed
2011-10-14 12:48:00 +02:00
return false ;
}
return ! empty ( $prohibits [ $context -> id ]);
2008-11-11 07:23:25 +00:00
}
2008-11-25 07:29:14 +00:00
/**
2011-10-14 12:48:00 +02:00
* More user friendly role permission changing ,
* it should produce as few overrides as possible .
2012-01-14 19:12:43 +01:00
*
2011-10-14 12:48:00 +02:00
* @ param int $roleid
2012-01-14 19:12:43 +01:00
* @ param stdClass $context
2011-10-14 12:48:00 +02:00
* @ param string $capname capability name
* @ param int $permission
* @ return void
2008-11-25 07:29:14 +00:00
*/
2011-10-14 12:48:00 +02:00
function role_change_permission ( $roleid , $context , $capname , $permission ) {
2008-11-25 07:29:14 +00:00
global $DB ;
2011-10-14 12:48:00 +02:00
if ( $permission == CAP_INHERIT ) {
unassign_capability ( $capname , $roleid , $context -> id );
return ;
2008-11-25 07:29:14 +00:00
}
2011-10-14 12:48:00 +02:00
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
2007-02-09 02:24:59 +00:00
2011-10-14 12:48:00 +02:00
$params = array ( 'roleid' => $roleid , 'cap' => $capname );
2007-09-19 06:52:34 +00:00
2011-10-14 12:48:00 +02:00
$sql = " SELECT ctx.id, rc.permission, ctx.depth
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
2019-02-28 08:39:20 +08:00
JOIN { capabilities } cap ON rc . capability = cap . name
2011-10-14 12:48:00 +02:00
WHERE rc . roleid = : roleid AND rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY ctx . depth DESC " ;
2007-02-09 02:24:59 +00:00
2011-10-14 12:48:00 +02:00
if ( $existing = $DB -> get_records_sql ( $sql , $params )) {
2020-05-06 09:14:49 +01:00
foreach ( $existing as $e ) {
2011-10-14 12:48:00 +02:00
if ( $e -> permission == CAP_PROHIBIT ) {
// prohibit can not be overridden, no point in changing anything
return ;
2007-02-09 02:24:59 +00:00
}
2011-10-14 12:48:00 +02:00
}
$lowest = array_shift ( $existing );
if ( $lowest -> permission == $permission ) {
// permission already set in this context or parent - nothing to do
return ;
}
if ( $existing ) {
$parent = array_shift ( $existing );
if ( $parent -> permission == $permission ) {
// permission already set in parent context or parent - just unset in this context
// we do this because we want as few overrides as possible for performance reasons
unassign_capability ( $capname , $roleid , $context -> id );
return ;
2009-07-13 08:37:34 +00:00
}
2011-10-14 12:48:00 +02:00
}
2007-02-09 02:24:59 +00:00
2011-10-14 12:48:00 +02:00
} else {
if ( $permission == CAP_PREVENT ) {
// nothing means role does not have permission
return ;
}
}
2007-02-09 02:24:59 +00:00
2011-10-14 12:48:00 +02:00
// assign the needed capability
assign_capability ( $capname , $permission , $roleid , $context -> id , true );
2007-02-09 02:24:59 +00:00
}
2006-09-20 08:30:49 +00:00
/**
2011-10-14 12:48:00 +02:00
* Basic moodle context abstraction class .
2009-05-19 07:50:54 +00:00
*
2012-02-21 11:48:33 +13:00
* Google confirms that no other important framework is using " context " class ,
* we could use something else like mcontext or moodle_context , but we need to type
* this very often which would be annoying and it would take too much space ...
*
* This class is derived from stdClass for backwards compatibility with
* odl $context record that was returned from DML $DB -> get_record ()
*
2012-01-14 19:12:43 +01:00
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-14 12:48:00 +02:00
*
* @ property - read int $id context id
* @ property - read int $contextlevel CONTEXT_SYSTEM , CONTEXT_COURSE , etc .
* @ property - read int $instanceid id of related instance in each context
* @ property - read string $path path to context , starts with system context
2012-02-21 11:48:33 +13:00
* @ property - read int $depth
2010-03-31 07:41:31 +00:00
*/
2012-03-28 11:38:53 +08:00
abstract class context extends stdClass implements IteratorAggregate {
2010-03-31 07:41:31 +00:00
2020-08-18 09:01:14 +01:00
/** @var string Default sorting of capabilities in {@see get_capabilities} */
protected const DEFAULT_CAPABILITY_SORT = 'contextlevel, component, name' ;
2012-02-21 11:48:33 +13:00
/**
* The context id
* Can be accessed publicly through $context -> id
* @ var int
2011-10-14 12:48:00 +02:00
*/
protected $_id ;
2012-02-21 11:48:33 +13:00
/**
* The context level
* Can be accessed publicly through $context -> contextlevel
* @ var int One of CONTEXT_ * e . g . CONTEXT_COURSE , CONTEXT_MODULE
*/
2011-10-14 12:48:00 +02:00
protected $_contextlevel ;
2012-02-21 11:48:33 +13:00
/**
* Id of the item this context is related to e . g . COURSE_CONTEXT => course . id
* Can be accessed publicly through $context -> instanceid
* @ var int
*/
2011-10-14 12:48:00 +02:00
protected $_instanceid ;
2012-02-21 11:48:33 +13:00
/**
* The path to the context always starting from the system context
* Can be accessed publicly through $context -> path
* @ var string
*/
2011-10-14 12:48:00 +02:00
protected $_path ;
2010-03-31 07:41:31 +00:00
2012-02-21 11:48:33 +13:00
/**
* The depth of the context in relation to parent contexts
* Can be accessed publicly through $context -> depth
* @ var int
*/
protected $_depth ;
2010-03-31 07:41:31 +00:00
2018-06-07 14:35:26 +08:00
/**
* Whether this context is locked or not .
*
* Can be accessed publicly through $context -> locked .
*
* @ var int
*/
protected $_locked ;
2012-02-21 11:48:33 +13:00
/**
* @ var array Context caching info
*/
2011-10-14 12:48:00 +02:00
private static $cache_contextsbyid = array ();
2012-02-21 11:48:33 +13:00
/**
* @ var array Context caching info
*/
2011-10-14 12:48:00 +02:00
private static $cache_contexts = array ();
2010-03-31 07:41:31 +00:00
2012-02-21 11:48:33 +13:00
/**
* Context count
* Why do we do count contexts ? Because count ( $array ) is horribly slow for large arrays
* @ var int
*/
protected static $cache_count = 0 ;
/**
* @ var array Context caching info
*/
2011-10-14 12:48:00 +02:00
protected static $cache_preloaded = array ();
2012-02-21 11:48:33 +13:00
/**
* @ var context_system The system context once initialised
*/
2011-10-14 12:48:00 +02:00
protected static $systemcontext = null ;
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
/**
* Resets the cache to remove all data .
2011-10-25 14:20:22 +02:00
* @ static
2011-10-14 12:48:00 +02:00
*/
protected static function reset_caches () {
self :: $cache_contextsbyid = array ();
self :: $cache_contexts = array ();
self :: $cache_count = 0 ;
self :: $cache_preloaded = array ();
2007-09-13 13:44:35 +00:00
2011-10-14 12:48:00 +02:00
self :: $systemcontext = null ;
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Adds a context to the cache . If the cache is full , discards a batch of
* older entries .
*
* @ static
* @ param context $context New context to add
* @ return void
*/
protected static function cache_add ( context $context ) {
if ( isset ( self :: $cache_contextsbyid [ $context -> id ])) {
// already cached, no need to do anything - this is relatively cheap, we do all this because count() is slow
return ;
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
if ( self :: $cache_count >= CONTEXT_CACHE_MAX_SIZE ) {
$i = 0 ;
2020-05-06 09:14:49 +01:00
foreach ( self :: $cache_contextsbyid as $ctx ) {
2011-10-14 12:48:00 +02:00
$i ++ ;
if ( $i <= 100 ) {
// we want to keep the first contexts to be loaded on this page, hopefully they will be needed again later
continue ;
}
if ( $i > ( CONTEXT_CACHE_MAX_SIZE / 3 )) {
// we remove oldest third of the contexts to make room for more contexts
break ;
}
unset ( self :: $cache_contextsbyid [ $ctx -> id ]);
unset ( self :: $cache_contexts [ $ctx -> contextlevel ][ $ctx -> instanceid ]);
self :: $cache_count -- ;
}
}
2006-08-14 08:14:02 +00:00
2011-10-14 12:48:00 +02:00
self :: $cache_contexts [ $context -> contextlevel ][ $context -> instanceid ] = $context ;
self :: $cache_contextsbyid [ $context -> id ] = $context ;
self :: $cache_count ++ ;
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Removes a context from the cache .
*
* @ static
* @ param context $context Context object to remove
* @ return void
*/
protected static function cache_remove ( context $context ) {
if ( ! isset ( self :: $cache_contextsbyid [ $context -> id ])) {
// not cached, no need to do anything - this is relatively cheap, we do all this because count() is slow
return ;
}
unset ( self :: $cache_contexts [ $context -> contextlevel ][ $context -> instanceid ]);
unset ( self :: $cache_contextsbyid [ $context -> id ]);
self :: $cache_count -- ;
if ( self :: $cache_count < 0 ) {
self :: $cache_count = 0 ;
}
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Gets a context from the cache .
*
* @ static
* @ param int $contextlevel Context level
* @ param int $instance Instance ID
* @ return context | bool Context or false if not in cache
*/
protected static function cache_get ( $contextlevel , $instance ) {
if ( isset ( self :: $cache_contexts [ $contextlevel ][ $instance ])) {
return self :: $cache_contexts [ $contextlevel ][ $instance ];
}
return false ;
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Gets a context from the cache based on its id .
*
* @ static
* @ param int $id Context ID
* @ return context | bool Context or false if not in cache
*/
protected static function cache_get_by_id ( $id ) {
if ( isset ( self :: $cache_contextsbyid [ $id ])) {
return self :: $cache_contextsbyid [ $id ];
}
return false ;
2010-03-31 07:41:31 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Preloads context information from db record and strips the cached info .
*
* @ static
* @ param stdClass $rec
* @ return void ( modifies $rec )
*/
2018-06-07 14:35:26 +08:00
protected static function preload_from_record ( stdClass $rec ) {
$notenoughdata = false ;
$notenoughdata = $notenoughdata || empty ( $rec -> ctxid );
$notenoughdata = $notenoughdata || empty ( $rec -> ctxlevel );
$notenoughdata = $notenoughdata || ! isset ( $rec -> ctxinstance );
$notenoughdata = $notenoughdata || empty ( $rec -> ctxpath );
$notenoughdata = $notenoughdata || empty ( $rec -> ctxdepth );
$notenoughdata = $notenoughdata || ! isset ( $rec -> ctxlocked );
if ( $notenoughdata ) {
// The record does not have enough data, passed here repeatedly or context does not exist yet.
if ( isset ( $rec -> ctxid ) && ! isset ( $rec -> ctxlocked )) {
debugging ( 'Locked value missing. Code is possibly not usings the getter properly.' , DEBUG_DEVELOPER );
}
return ;
}
$record = ( object ) [
'id' => $rec -> ctxid ,
'contextlevel' => $rec -> ctxlevel ,
'instanceid' => $rec -> ctxinstance ,
'path' => $rec -> ctxpath ,
'depth' => $rec -> ctxdepth ,
'locked' => $rec -> ctxlocked ,
];
unset ( $rec -> ctxid );
unset ( $rec -> ctxlevel );
unset ( $rec -> ctxinstance );
unset ( $rec -> ctxpath );
unset ( $rec -> ctxdepth );
unset ( $rec -> ctxlocked );
return context :: create_instance_from_record ( $record );
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
// ====== magic methods =======
2008-02-29 08:44:23 +00:00
2011-10-14 12:48:00 +02:00
/**
* Magic setter method , we do not want anybody to modify properties from the outside
* @ param string $name
2012-02-21 11:48:33 +13:00
* @ param mixed $value
2011-10-14 12:48:00 +02:00
*/
public function __set ( $name , $value ) {
debugging ( 'Can not change context instance properties!' );
}
2008-02-29 08:44:23 +00:00
2011-10-14 12:48:00 +02:00
/**
* Magic method getter , redirects to read only values .
* @ param string $name
* @ return mixed
*/
public function __get ( $name ) {
switch ( $name ) {
2018-06-07 14:35:26 +08:00
case 'id' :
return $this -> _id ;
case 'contextlevel' :
return $this -> _contextlevel ;
case 'instanceid' :
return $this -> _instanceid ;
case 'path' :
return $this -> _path ;
case 'depth' :
return $this -> _depth ;
case 'locked' :
return $this -> is_locked ();
2011-10-14 12:48:00 +02:00
default :
debugging ( 'Invalid context property accessed! ' . $name );
return null ;
2008-02-29 08:44:23 +00:00
}
2006-08-15 08:29:29 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Full support for isset on our magic read only properties .
2012-02-21 11:48:33 +13:00
* @ param string $name
2011-10-14 12:48:00 +02:00
* @ return bool
*/
public function __isset ( $name ) {
switch ( $name ) {
2018-06-07 14:35:26 +08:00
case 'id' :
return isset ( $this -> _id );
case 'contextlevel' :
return isset ( $this -> _contextlevel );
case 'instanceid' :
return isset ( $this -> _instanceid );
case 'path' :
return isset ( $this -> _path );
case 'depth' :
return isset ( $this -> _depth );
case 'locked' :
// Locked is always set.
return true ;
default :
return false ;
2011-10-14 12:48:00 +02:00
}
2006-08-18 08:01:16 +00:00
}
2011-10-14 12:48:00 +02:00
/**
2018-06-07 14:35:26 +08:00
* All properties are read only , sorry .
2011-10-14 12:48:00 +02:00
* @ param string $name
*/
public function __unset ( $name ) {
debugging ( 'Can not unset context instance properties!' );
2006-08-18 08:01:16 +00:00
}
2006-09-20 21:00:45 +00:00
2012-03-28 11:38:53 +08:00
// ====== implementing method from interface IteratorAggregate ======
/**
* Create an iterator because magic vars can 't be seen by ' foreach ' .
*
* Now we can convert context object to array using convert_to_array (),
* and feed it properly to json_encode () .
*/
2021-12-21 10:39:00 +01:00
public function getIterator () : Traversable {
2012-03-28 11:38:53 +08:00
$ret = array (
'id' => $this -> id ,
'contextlevel' => $this -> contextlevel ,
'instanceid' => $this -> instanceid ,
'path' => $this -> path ,
2018-06-07 14:35:26 +08:00
'depth' => $this -> depth ,
'locked' => $this -> locked ,
2012-03-28 11:38:53 +08:00
);
return new ArrayIterator ( $ret );
}
2011-10-14 12:48:00 +02:00
// ====== general context methods ======
2006-08-18 08:01:16 +00:00
2011-10-14 12:48:00 +02:00
/**
* Constructor is protected so that devs are forced to
* use context_xxx :: instance () or context :: instance_by_id () .
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
2014-01-29 10:01:17 +08:00
$this -> _id = ( int ) $record -> id ;
2011-10-14 12:48:00 +02:00
$this -> _contextlevel = ( int ) $record -> contextlevel ;
$this -> _instanceid = $record -> instanceid ;
$this -> _path = $record -> path ;
$this -> _depth = $record -> depth ;
2018-06-07 14:35:26 +08:00
if ( isset ( $record -> locked )) {
$this -> _locked = $record -> locked ;
} else if ( ! during_initial_install () && ! moodle_needs_upgrading ()) {
debugging ( 'Locked value missing. Code is possibly not usings the getter properly.' , DEBUG_DEVELOPER );
}
2011-10-14 12:48:00 +02:00
}
2010-03-31 07:41:31 +00:00
2011-10-14 12:48:00 +02:00
/**
* This function is also used to work around 'protected' keyword problems in context_helper .
2011-10-25 14:20:22 +02:00
* @ static
2011-10-14 12:48:00 +02:00
* @ param stdClass $record
* @ return context instance
*/
protected static function create_instance_from_record ( stdClass $record ) {
$classname = context_helper :: get_class_for_level ( $record -> contextlevel );
2006-09-23 12:51:00 +00:00
2011-10-14 12:48:00 +02:00
if ( $context = context :: cache_get_by_id ( $record -> id )) {
return $context ;
}
2006-08-19 08:12:45 +00:00
2011-10-14 12:48:00 +02:00
$context = new $classname ( $record );
context :: cache_add ( $context );
return $context ;
}
/**
* Copy prepared new contexts from temp table to context table ,
* we do this in db specific way for perf reasons only .
* @ static
*/
protected static function merge_context_temp_table () {
global $DB ;
/* MDL - 11347 :
* - mysql does not allow to use FROM in UPDATE statements
* - using two tables after UPDATE works in mysql , but might give unexpected
* results in pg 8 ( depends on configuration )
* - using table alias in UPDATE does not work in pg < 8.2
*
* Different code for each database - mostly for performance reasons
*/
$dbfamily = $DB -> get_dbfamily ();
if ( $dbfamily == 'mysql' ) {
$updatesql = " UPDATE { context} ct, { context_temp} temp
SET ct . path = temp . path ,
2018-06-07 14:35:26 +08:00
ct . depth = temp . depth ,
ct . locked = temp . locked
2011-10-14 12:48:00 +02:00
WHERE ct . id = temp . id " ;
} else if ( $dbfamily == 'oracle' ) {
$updatesql = " UPDATE { context} ct
2018-06-07 14:35:26 +08:00
SET ( ct . path , ct . depth , ct . locked ) =
( SELECT temp . path , temp . depth , temp . locked
2011-10-14 12:48:00 +02:00
FROM { context_temp } temp
WHERE temp . id = ct . id )
WHERE EXISTS ( SELECT 'x'
FROM { context_temp } temp
WHERE temp . id = ct . id ) " ;
} else if ( $dbfamily == 'postgres' or $dbfamily == 'mssql' ) {
$updatesql = " UPDATE { context}
SET path = temp . path ,
2018-06-07 14:35:26 +08:00
depth = temp . depth ,
locked = temp . locked
2011-10-14 12:48:00 +02:00
FROM { context_temp } temp
WHERE temp . id = { context } . id " ;
} else {
// sqlite and others
$updatesql = " UPDATE { context}
SET path = ( SELECT path FROM { context_temp } WHERE id = { context } . id ),
2018-06-07 14:35:26 +08:00
depth = ( SELECT depth FROM { context_temp } WHERE id = { context } . id ),
locked = ( SELECT locked FROM { context_temp } WHERE id = { context } . id )
2011-10-14 12:48:00 +02:00
WHERE id IN ( SELECT id FROM { context_temp }) " ;
2006-08-19 08:12:45 +00:00
}
2011-10-14 12:48:00 +02:00
$DB -> execute ( $updatesql );
2006-08-19 08:12:45 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Get a context instance as an object , from a given context id .
*
* @ static
* @ param int $id context id
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* MUST_EXIST means throw exception if no record found
* @ return context | bool the context object or false if not found
*/
public static function instance_by_id ( $id , $strictness = MUST_EXIST ) {
global $DB ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( get_called_class () !== 'context' and get_called_class () !== 'context_helper' ) {
// some devs might confuse context->id and instanceid, better prevent these mistakes completely
throw new coding_exception ( 'use only context::instance_by_id() for real context levels use ::instance() methods' );
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( $id == SYSCONTEXTID ) {
return context_system :: instance ( 0 , $strictness );
}
2008-02-05 12:59:28 +00:00
2011-10-14 12:48:00 +02:00
if ( is_array ( $id ) or is_object ( $id ) or empty ( $id )) {
throw new coding_exception ( 'Invalid context id specified context::instance_by_id()' );
}
2006-08-18 08:01:16 +00:00
2011-10-14 12:48:00 +02:00
if ( $context = context :: cache_get_by_id ( $id )) {
return $context ;
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( $record = $DB -> get_record ( 'context' , array ( 'id' => $id ), '*' , $strictness )) {
return context :: create_instance_from_record ( $record );
}
2006-08-23 06:36:08 +00:00
2011-10-14 12:48:00 +02:00
return false ;
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
/**
* Update context info after moving context in the tree structure .
*
* @ param context $newparent
* @ return void
*/
public function update_moved ( context $newparent ) {
global $DB ;
2009-03-25 04:20:57 +00:00
2011-10-14 12:48:00 +02:00
$frompath = $this -> _path ;
$newpath = $newparent -> path . '/' . $this -> _id ;
2009-03-25 04:20:57 +00:00
2011-10-14 12:48:00 +02:00
$trans = $DB -> start_delegated_transaction ();
2006-08-23 06:36:08 +00:00
2011-10-14 12:48:00 +02:00
$setdepth = '' ;
if (( $newparent -> depth + 1 ) != $this -> _depth ) {
$diff = $newparent -> depth - $this -> _depth + 1 ;
$setdepth = " , depth = depth + $diff " ;
}
$sql = " UPDATE { context}
SET path = ?
$setdepth
WHERE id = ? " ;
$params = array ( $newpath , $this -> _id );
$DB -> execute ( $sql , $params );
$this -> _path = $newpath ;
$this -> _depth = $newparent -> depth + 1 ;
$sql = " UPDATE { context}
SET path = " . $DB->sql_concat ( " ? " , $DB->sql_substr ( " path " , strlen( $frompath )+1)). "
$setdepth
WHERE path LIKE ? " ;
$params = array ( $newpath , " { $frompath } /% " );
$DB -> execute ( $sql , $params );
$this -> mark_dirty ();
context :: reset_caches ();
$trans -> allow_commit ();
2010-07-19 17:51:17 +00:00
}
2018-06-07 14:35:26 +08:00
/**
* Set whether this context has been locked or not .
*
* @ param bool $locked
* @ return $this
*/
public function set_locked ( bool $locked ) {
global $DB ;
if ( $this -> _locked == $locked ) {
return $this ;
}
$this -> _locked = $locked ;
$DB -> set_field ( 'context' , 'locked' , ( int ) $locked , [ 'id' => $this -> id ]);
$this -> mark_dirty ();
2019-08-09 11:27:40 +01:00
if ( $locked ) {
$eventname = '\\core\\event\\context_locked' ;
} else {
$eventname = '\\core\\event\\context_unlocked' ;
}
$event = $eventname :: create ([ 'context' => $this , 'objectid' => $this -> id ]);
$event -> trigger ();
2018-06-07 14:35:26 +08:00
self :: reset_caches ();
return $this ;
}
2011-10-14 12:48:00 +02:00
/**
* Remove all context path info and optionally rebuild it .
*
* @ param bool $rebuild
* @ return void
*/
public function reset_paths ( $rebuild = true ) {
global $DB ;
if ( $this -> _path ) {
$this -> mark_dirty ();
}
$DB -> set_field_select ( 'context' , 'depth' , 0 , " path LIKE '%/ $this->_id /%' " );
$DB -> set_field_select ( 'context' , 'path' , NULL , " path LIKE '%/ $this->_id /%' " );
if ( $this -> _contextlevel != CONTEXT_SYSTEM ) {
$DB -> set_field ( 'context' , 'depth' , 0 , array ( 'id' => $this -> _id ));
$DB -> set_field ( 'context' , 'path' , NULL , array ( 'id' => $this -> _id ));
$this -> _depth = 0 ;
$this -> _path = null ;
2008-11-06 07:34:01 +00:00
}
2008-07-23 16:10:06 +00:00
2011-10-14 12:48:00 +02:00
if ( $rebuild ) {
context_helper :: build_all_paths ( false );
}
2008-07-23 16:10:06 +00:00
2011-10-14 12:48:00 +02:00
context :: reset_caches ();
2008-10-30 06:26:18 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Delete all data linked to content , do not delete the context record itself
*/
public function delete_content () {
global $CFG , $DB ;
2008-10-30 06:26:18 +00:00
2011-10-14 12:48:00 +02:00
blocks_delete_all_for_context ( $this -> _id );
filter_delete_all_for_context ( $this -> _id );
require_once ( $CFG -> dirroot . '/comment/lib.php' );
comment :: delete_comments ( array ( 'contextid' => $this -> _id ));
require_once ( $CFG -> dirroot . '/rating/lib.php' );
$delopt = new stdclass ();
$delopt -> contextid = $this -> _id ;
$rm = new rating_manager ();
$rm -> delete_ratings ( $delopt );
// delete all files attached to this context
$fs = get_file_storage ();
$fs -> delete_area_files ( $this -> _id );
2013-06-06 11:50:58 +08:00
// Delete all repository instances attached to this context.
require_once ( $CFG -> dirroot . '/repository/lib.php' );
repository :: delete_all_for_context ( $this -> _id );
2011-11-13 13:50:00 +01:00
// delete all advanced grading data attached to this context
require_once ( $CFG -> dirroot . '/grade/grading/lib.php' );
grading_manager :: delete_all_for_context ( $this -> _id );
2011-10-14 12:48:00 +02:00
// now delete stuff from role related tables, role_unassign_all
// and unenrol should be called earlier to do proper cleanup
$DB -> delete_records ( 'role_assignments' , array ( 'contextid' => $this -> _id ));
$DB -> delete_records ( 'role_names' , array ( 'contextid' => $this -> _id ));
2018-06-22 17:16:14 -04:00
$this -> delete_capabilities ();
}
2016-05-14 21:14:31 +09:30
2018-06-22 17:16:14 -04:00
/**
* Unassign all capabilities from a context .
*/
public function delete_capabilities () {
global $DB ;
$ids = $DB -> get_fieldset_select ( 'role_capabilities' , 'DISTINCT roleid' , 'contextid = ?' , array ( $this -> _id ));
2016-05-14 21:14:31 +09:30
if ( $ids ) {
2018-06-22 17:16:14 -04:00
$DB -> delete_records ( 'role_capabilities' , array ( 'contextid' => $this -> _id ));
2016-05-14 21:14:31 +09:30
// Reset any cache of these roles, including MUC.
2017-03-27 11:44:43 +01:00
accesslib_clear_role_cache ( $ids );
2016-05-14 21:14:31 +09:30
}
2009-01-17 23:16:20 +00:00
}
2007-09-19 07:27:46 +00:00
2011-10-14 12:48:00 +02:00
/**
* Delete the context content and the context record itself
*/
public function delete () {
global $DB ;
2013-12-16 09:44:04 +08:00
if ( $this -> _contextlevel <= CONTEXT_SYSTEM ) {
throw new coding_exception ( 'Cannot delete system context' );
}
2011-10-14 12:48:00 +02:00
// double check the context still exists
if ( ! $DB -> record_exists ( 'context' , array ( 'id' => $this -> _id ))) {
context :: cache_remove ( $this );
return ;
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
}
2011-10-14 12:48:00 +02:00
$this -> delete_content ();
$DB -> delete_records ( 'context' , array ( 'id' => $this -> _id ));
// purge static context cache if entry present
context :: cache_remove ( $this );
2019-08-08 10:38:51 +01:00
// Inform search engine to delete data related to this context.
\core_search\manager :: context_deleted ( $this );
2008-10-30 06:26:18 +00:00
}
2008-04-18 06:21:00 +00:00
2011-10-14 12:48:00 +02:00
// ====== context level related methods ======
/**
* Utility method for context creation
*
* @ static
* @ param int $contextlevel
* @ param int $instanceid
* @ param string $parentpath
* @ return stdClass context record
*/
protected static function insert_context_record ( $contextlevel , $instanceid , $parentpath ) {
global $DB ;
$record = new stdClass ();
$record -> contextlevel = $contextlevel ;
$record -> instanceid = $instanceid ;
$record -> depth = 0 ;
$record -> path = null ; //not known before insert
2018-06-07 14:35:26 +08:00
$record -> locked = 0 ;
2011-10-14 12:48:00 +02:00
$record -> id = $DB -> insert_record ( 'context' , $record );
// now add path if known - it can be added later
if ( ! is_null ( $parentpath )) {
$record -> path = $parentpath . '/' . $record -> id ;
$record -> depth = substr_count ( $record -> path , '/' );
$DB -> update_record ( 'context' , $record );
}
return $record ;
2008-10-30 06:26:18 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with the
* type of context , e . g . User , Course , Forum , etc .
* @ param boolean $short whether to use the short name of the thing . Only applies
* to course contexts
2021-03-31 15:33:57 +02:00
* @ param boolean $escape Whether the returned name of the thing is to be
* HTML escaped or not .
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
// must be implemented in all context levels
throw new coding_exception ( 'can not get name of abstract context' );
}
2008-02-15 16:40:45 +00:00
2018-06-07 14:35:26 +08:00
/**
* Whether the current context is locked .
*
* @ return bool
*/
public function is_locked () {
if ( $this -> _locked ) {
return true ;
}
if ( $parent = $this -> get_parent_context ()) {
2018-11-13 08:03:49 +08:00
return $parent -> is_locked ();
2018-06-07 14:35:26 +08:00
}
return false ;
}
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public abstract function get_url ();
2008-02-15 16:40:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort SQL order by snippet for sorting returned capabilities sensibly for display
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public abstract function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT );
2009-03-23 08:15:21 +00:00
2011-10-14 12:48:00 +02:00
/**
* Recursive function which , given a context , find all its children context ids .
*
* For course category contexts it will return immediate children and all subcategory contexts .
* It will NOT recurse into courses or subcategories categories .
* If you want to do that , call it on the returned courses / categories .
*
* When called for a course context , it will return the modules and blocks
* displayed in the course page and blocks displayed on the module pages .
*
* If called on a user / course / module context it _will_ populate the cache with the appropriate
* contexts ; - )
*
* @ return array Array of child records
*/
public function get_child_contexts () {
global $DB ;
2009-03-23 08:15:21 +00:00
2013-12-16 09:44:04 +08:00
if ( empty ( $this -> _path ) or empty ( $this -> _depth )) {
debugging ( 'Can not find child contexts of context ' . $this -> _id . ' try rebuilding of context paths' );
return array ();
}
2011-10-14 12:48:00 +02:00
$sql = " SELECT ctx.*
FROM { context } ctx
WHERE ctx . path LIKE ? " ;
$params = array ( $this -> _path . '/%' );
$records = $DB -> get_records_sql ( $sql , $params );
2009-03-23 08:15:21 +00:00
2011-10-14 12:48:00 +02:00
$result = array ();
foreach ( $records as $record ) {
$result [ $record -> id ] = context :: create_instance_from_record ( $record );
}
2008-02-15 16:40:45 +00:00
2011-10-14 12:48:00 +02:00
return $result ;
}
2006-08-23 06:36:08 +00:00
2020-07-20 12:28:35 +08:00
/**
* Determine if the current context is a parent of the possible child .
*
* @ param context $possiblechild
* @ param bool $includeself Whether to check the current context
* @ return bool
*/
public function is_parent_of ( context $possiblechild , bool $includeself ) : bool {
// A simple substring check is used on the context path.
// The possible child's path is used as a haystack, with the current context as the needle.
// The path is prefixed with '+' to ensure that the parent always starts at the top.
// It is suffixed with '+' to ensure that parents are not included.
// The needle always suffixes with a '/' to ensure that the contextid uses a complete match (i.e. 142/ instead of 14).
// The haystack is suffixed with '/+' if $includeself is true to allow the current context to match.
// The haystack is suffixed with '+' if $includeself is false to prevent the current context from matching.
$haystacksuffix = $includeself ? '/+' : '+' ;
$strpos = strpos (
" + { $possiblechild -> path } { $haystacksuffix } " ,
" + { $this -> path } / "
);
return $strpos === 0 ;
}
2011-10-14 12:48:00 +02:00
/**
* Returns parent contexts of this context in reversed order , i . e . parent first ,
* then grand parent , etc .
*
2018-06-21 13:23:03 -04:00
* @ param bool $includeself true means include self too
2011-10-14 12:48:00 +02:00
* @ return array of context instances
*/
public function get_parent_contexts ( $includeself = false ) {
if ( ! $contextids = $this -> get_parent_context_ids ( $includeself )) {
2008-11-06 07:34:01 +00:00
return array ();
}
2008-07-23 16:10:06 +00:00
2018-10-17 13:36:39 +08:00
// Preload the contexts to reduce DB calls.
context_helper :: preload_contexts_by_id ( $contextids );
2011-10-14 12:48:00 +02:00
$result = array ();
foreach ( $contextids as $contextid ) {
$parent = context :: instance_by_id ( $contextid , MUST_EXIST );
$result [ $parent -> id ] = $parent ;
}
2008-07-23 16:10:06 +00:00
2011-10-14 12:48:00 +02:00
return $result ;
2008-11-05 08:17:30 +00:00
}
2020-07-20 12:28:35 +08:00
/**
* Determine if the current context is a child of the possible parent .
*
* @ param context $possibleparent
* @ param bool $includeself Whether to check the current context
* @ return bool
*/
public function is_child_of ( context $possibleparent , bool $includeself ) : bool {
// A simple substring check is used on the context path.
// The current context is used as a haystack, with the possible parent as the needle.
// The path is prefixed with '+' to ensure that the parent always starts at the top.
// It is suffixed with '+' to ensure that children are not included.
// The needle always suffixes with a '/' to ensure that the contextid uses a complete match (i.e. 142/ instead of 14).
// The haystack is suffixed with '/+' if $includeself is true to allow the current context to match.
// The haystack is suffixed with '+' if $includeself is false to prevent the current context from matching.
$haystacksuffix = $includeself ? '/+' : '+' ;
$strpos = strpos (
" + { $this -> path } { $haystacksuffix } " ,
" + { $possibleparent -> path } / "
);
return $strpos === 0 ;
}
2011-10-14 12:48:00 +02:00
/**
2018-06-21 13:23:03 -04:00
* Returns parent context ids of this context in reversed order , i . e . parent first ,
2011-10-14 12:48:00 +02:00
* then grand parent , etc .
*
2018-06-21 13:23:03 -04:00
* @ param bool $includeself true means include self too
2011-10-14 12:48:00 +02:00
* @ return array of context ids
*/
public function get_parent_context_ids ( $includeself = false ) {
if ( empty ( $this -> _path )) {
return array ();
}
$parentcontexts = trim ( $this -> _path , '/' ); // kill leading slash
$parentcontexts = explode ( '/' , $parentcontexts );
if ( ! $includeself ) {
array_pop ( $parentcontexts ); // and remove its own id
}
return array_reverse ( $parentcontexts );
2008-11-05 08:17:30 +00:00
}
2018-06-21 13:23:03 -04:00
/**
* Returns parent context paths of this context .
*
* @ param bool $includeself true means include self too
* @ return array of context paths
*/
public function get_parent_context_paths ( $includeself = false ) {
if ( empty ( $this -> _path )) {
return array ();
}
$contextids = explode ( '/' , $this -> _path );
$path = '' ;
$paths = array ();
foreach ( $contextids as $contextid ) {
if ( $contextid ) {
$path .= '/' . $contextid ;
$paths [ $contextid ] = $path ;
}
}
if ( ! $includeself ) {
unset ( $paths [ $this -> _id ]);
}
return $paths ;
}
2011-10-14 12:48:00 +02:00
/**
* Returns parent context
*
* @ return context
*/
public function get_parent_context () {
if ( empty ( $this -> _path ) or $this -> _id == SYSCONTEXTID ) {
return false ;
}
2009-11-01 11:31:16 +00:00
2011-10-14 12:48:00 +02:00
$parentcontexts = trim ( $this -> _path , '/' ); // kill leading slash
$parentcontexts = explode ( '/' , $parentcontexts );
array_pop ( $parentcontexts ); // self
$contextid = array_pop ( $parentcontexts ); // immediate parent
return context :: instance_by_id ( $contextid , MUST_EXIST );
2008-07-23 16:10:06 +00:00
}
2006-09-17 07:00:47 +00:00
2011-10-14 12:48:00 +02:00
/**
* Is this context part of any course ? If yes return course context .
*
* @ param bool $strict true means throw exception if not found , false means return false if not found
2014-04-15 15:46:19 +08:00
* @ return context_course context of the enclosing course , null if not found or exception
2011-10-14 12:48:00 +02:00
*/
public function get_course_context ( $strict = true ) {
if ( $strict ) {
throw new coding_exception ( 'Context does not belong to any course.' );
} else {
return false ;
2008-11-05 08:17:30 +00:00
}
}
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
throw new coding_exception ( 'get_cleanup_sql() method must be implemented in all context levels' );
2006-09-17 07:00:47 +00:00
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
* @ return void
*/
protected static function build_paths ( $force ) {
throw new coding_exception ( 'build_paths() method must be implemented in all context levels' );
}
2008-11-05 08:17:30 +00:00
2011-10-14 12:48:00 +02:00
/**
* Create missing context instances at given level
*
* @ static
* @ return void
*/
protected static function create_level_instances () {
throw new coding_exception ( 'create_level_instances() method must be implemented in all context levels' );
2008-11-05 08:17:30 +00:00
}
2006-08-28 08:42:30 +00:00
2011-10-14 12:48:00 +02:00
/**
* Reset all cached permissions and definitions if the necessary .
* @ return void
*/
public function reload_if_dirty () {
global $ACCESSLIB_PRIVATE , $USER ;
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2011-10-14 12:48:00 +02:00
// Load dirty contexts list if needed
if ( CLI_SCRIPT ) {
if ( ! isset ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
// we do not load dirty flags in CLI and cron
$ACCESSLIB_PRIVATE -> dirtycontexts = array ();
}
} else {
2018-06-05 16:37:25 -04:00
if ( ! isset ( $USER -> access [ 'time' ])) {
// Nothing has been loaded yet, so we do not need to check dirty flags now.
return ;
}
// From skodak: No idea why -2 is there, server cluster time difference maybe...
$changedsince = $USER -> access [ 'time' ] - 2 ;
2011-10-14 12:48:00 +02:00
if ( ! isset ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
2018-06-05 16:37:25 -04:00
$ACCESSLIB_PRIVATE -> dirtycontexts = get_cache_flags ( 'accesslib/dirtycontexts' , $changedsince );
}
if ( ! isset ( $ACCESSLIB_PRIVATE -> dirtyusers [ $USER -> id ])) {
$ACCESSLIB_PRIVATE -> dirtyusers [ $USER -> id ] = get_cache_flag ( 'accesslib/dirtyusers' , $USER -> id , $changedsince );
2011-10-14 12:48:00 +02:00
}
}
2018-06-05 16:37:25 -04:00
$dirty = false ;
if ( ! empty ( $ACCESSLIB_PRIVATE -> dirtyusers [ $USER -> id ])) {
$dirty = true ;
2018-06-21 13:23:03 -04:00
} else if ( ! empty ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
$paths = $this -> get_parent_context_paths ( true );
foreach ( $paths as $path ) {
if ( isset ( $ACCESSLIB_PRIVATE -> dirtycontexts [ $path ])) {
2018-06-05 16:37:25 -04:00
$dirty = true ;
break ;
}
2011-10-14 12:48:00 +02:00
}
}
2018-06-05 16:37:25 -04:00
if ( $dirty ) {
// Reload all capabilities of USER and others - preserving loginas, roleswitches, etc.
// Then cleanup any marks of dirtyness... at least from our short term memory!
reload_all_capabilities ();
}
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Mark a context as dirty ( with timestamp ) so as to force reloading of the context .
*/
public function mark_dirty () {
global $CFG , $USER , $ACCESSLIB_PRIVATE ;
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2011-10-14 12:48:00 +02:00
if ( during_initial_install ()) {
return ;
}
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2011-10-14 12:48:00 +02:00
// only if it is a non-empty string
if ( is_string ( $this -> _path ) && $this -> _path !== '' ) {
set_cache_flag ( 'accesslib/dirtycontexts' , $this -> _path , 1 , time () + $CFG -> sessiontimeout );
if ( isset ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
$ACCESSLIB_PRIVATE -> dirtycontexts [ $this -> _path ] = 1 ;
} else {
if ( CLI_SCRIPT ) {
$ACCESSLIB_PRIVATE -> dirtycontexts = array ( $this -> _path => 1 );
} else {
if ( isset ( $USER -> access [ 'time' ])) {
$ACCESSLIB_PRIVATE -> dirtycontexts = get_cache_flags ( 'accesslib/dirtycontexts' , $USER -> access [ 'time' ] - 2 );
} else {
$ACCESSLIB_PRIVATE -> dirtycontexts = array ( $this -> _path => 1 );
}
// flags not loaded yet, it will be done later in $context->reload_if_dirty()
}
}
}
}
2008-11-06 07:34:01 +00:00
}
2008-11-13 08:11:10 +00:00
2011-10-23 12:50:56 +02:00
/**
* Context maintenance and helper methods .
*
* This is " extends context " is a bloody hack that tires to work around the deficiencies
* in the " protected " keyword in PHP , this helps us to hide all the internals of context
* level implementation from the rest of code , the code completion returns what developers need .
*
* Thank you Tim Hunt for helping me with this nasty trick .
*
2012-01-14 19:12:43 +01:00
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-23 12:50:56 +02:00
*/
class context_helper extends context {
2012-02-21 11:48:33 +13:00
/**
* @ var array An array mapping context levels to classes
*/
2013-08-24 21:09:36 +02:00
private static $alllevels ;
/**
* Instance does not make sense here , only static use
*/
protected function __construct () {
}
2014-01-14 11:25:10 -05:00
/**
* Reset internal context levels array .
*/
public static function reset_levels () {
self :: $alllevels = null ;
}
2013-08-24 21:09:36 +02:00
/**
* Initialise context levels , call before using self :: $alllevels .
*/
private static function init_levels () {
global $CFG ;
if ( isset ( self :: $alllevels )) {
return ;
}
self :: $alllevels = array (
2011-10-23 12:50:56 +02:00
CONTEXT_SYSTEM => 'context_system' ,
CONTEXT_USER => 'context_user' ,
CONTEXT_COURSECAT => 'context_coursecat' ,
CONTEXT_COURSE => 'context_course' ,
CONTEXT_MODULE => 'context_module' ,
CONTEXT_BLOCK => 'context_block' ,
2013-08-24 21:09:36 +02:00
);
2011-10-23 12:50:56 +02:00
2013-08-24 21:09:36 +02:00
if ( empty ( $CFG -> custom_context_classes )) {
return ;
}
2014-01-14 11:25:10 -05:00
$levels = $CFG -> custom_context_classes ;
if ( ! is_array ( $levels )) {
$levels = @ unserialize ( $levels );
}
if ( ! is_array ( $levels )) {
debugging ( 'Invalid $CFG->custom_context_classes detected, value ignored.' , DEBUG_DEVELOPER );
return ;
}
2013-08-24 21:09:36 +02:00
// Unsupported custom levels, use with care!!!
2014-01-14 11:25:10 -05:00
foreach ( $levels as $level => $classname ) {
2013-08-24 21:09:36 +02:00
self :: $alllevels [ $level ] = $classname ;
}
ksort ( self :: $alllevels );
2011-10-23 12:50:56 +02:00
}
/**
* Returns a class name of the context level class
*
* @ static
* @ param int $contextlevel ( CONTEXT_SYSTEM , etc . )
* @ return string class name of the context class
*/
public static function get_class_for_level ( $contextlevel ) {
2013-08-24 21:09:36 +02:00
self :: init_levels ();
2011-10-23 12:50:56 +02:00
if ( isset ( self :: $alllevels [ $contextlevel ])) {
return self :: $alllevels [ $contextlevel ];
} else {
throw new coding_exception ( 'Invalid context level specified' );
}
}
/**
* Returns a list of all context levels
*
* @ static
* @ return array int => string ( level => level class name )
*/
public static function get_all_levels () {
2013-08-24 21:09:36 +02:00
self :: init_levels ();
2011-10-23 12:50:56 +02:00
return self :: $alllevels ;
}
/**
* Remove stale contexts that belonged to deleted instances .
* Ideally all code should cleanup contexts properly , unfortunately accidents happen ...
*
* @ static
* @ return void
*/
public static function cleanup_instances () {
global $DB ;
2013-08-24 21:09:36 +02:00
self :: init_levels ();
2011-10-23 12:50:56 +02:00
$sqls = array ();
foreach ( self :: $alllevels as $level => $classname ) {
$sqls [] = $classname :: get_cleanup_sql ();
}
$sql = implode ( " UNION " , $sqls );
// it is probably better to use transactions, it might be faster too
$transaction = $DB -> start_delegated_transaction ();
$rs = $DB -> get_recordset_sql ( $sql );
foreach ( $rs as $record ) {
$context = context :: create_instance_from_record ( $record );
$context -> delete ();
}
$rs -> close ();
$transaction -> allow_commit ();
}
/**
* Create all context instances at the given level and above .
*
* @ static
* @ param int $contextlevel null means all levels
* @ param bool $buildpaths
* @ return void
*/
public static function create_instances ( $contextlevel = null , $buildpaths = true ) {
2013-08-24 21:09:36 +02:00
self :: init_levels ();
2011-10-23 12:50:56 +02:00
foreach ( self :: $alllevels as $level => $classname ) {
if ( $contextlevel and $level > $contextlevel ) {
// skip potential sub-contexts
continue ;
}
$classname :: create_level_instances ();
if ( $buildpaths ) {
$classname :: build_paths ( false );
}
}
}
/**
* Rebuild paths and depths in all context levels .
*
* @ static
* @ param bool $force false means add missing only
* @ return void
*/
public static function build_all_paths ( $force = false ) {
2013-08-24 21:09:36 +02:00
self :: init_levels ();
2011-10-23 12:50:56 +02:00
foreach ( self :: $alllevels as $classname ) {
$classname :: build_paths ( $force );
}
// reset static course cache - it might have incorrect cached data
accesslib_clear_all_caches ( true );
}
/**
* Resets the cache to remove all data .
* @ static
*/
public static function reset_caches () {
context :: reset_caches ();
}
/**
* Returns all fields necessary for context preloading from user $rec .
*
* This helps with performance when dealing with hundreds of contexts .
*
* @ static
* @ param string $tablealias context table alias in the query
* @ return array ( table . column => alias , ... )
*/
public static function get_preload_record_columns ( $tablealias ) {
2018-06-07 14:35:26 +08:00
return [
" $tablealias .id " => " ctxid " ,
" $tablealias .path " => " ctxpath " ,
" $tablealias .depth " => " ctxdepth " ,
" $tablealias .contextlevel " => " ctxlevel " ,
" $tablealias .instanceid " => " ctxinstance " ,
" $tablealias .locked " => " ctxlocked " ,
];
2011-10-23 12:50:56 +02:00
}
/**
* Returns all fields necessary for context preloading from user $rec .
*
* This helps with performance when dealing with hundreds of contexts .
*
* @ static
* @ param string $tablealias context table alias in the query
* @ return string
*/
public static function get_preload_record_columns_sql ( $tablealias ) {
2018-06-07 14:35:26 +08:00
return " $tablealias .id AS ctxid, " .
" $tablealias .path AS ctxpath, " .
" $tablealias .depth AS ctxdepth, " .
" $tablealias .contextlevel AS ctxlevel, " .
" $tablealias .instanceid AS ctxinstance, " .
" $tablealias .locked AS ctxlocked " ;
2011-10-23 12:50:56 +02:00
}
/**
2023-01-24 21:25:54 +00:00
* Preloads context cache with information from db record and strips the cached info .
2011-10-23 12:50:56 +02:00
*
* The db request has to contain all columns from context_helper :: get_preload_record_columns () .
*
* @ static
* @ param stdClass $rec
2023-01-24 21:25:54 +00:00
* @ return void This is intentional . See MDL - 37115. You will need to get the context
* in the normal way , but it is now cached , so that will be fast .
2011-10-23 12:50:56 +02:00
*/
public static function preload_from_record ( stdClass $rec ) {
context :: preload_from_record ( $rec );
}
2018-10-17 13:36:39 +08:00
/**
* Preload a set of contexts using their contextid .
*
* @ param array $contextids
*/
public static function preload_contexts_by_id ( array $contextids ) {
global $DB ;
// Determine which contexts are not already cached.
$tofetch = [];
foreach ( $contextids as $contextid ) {
if ( ! self :: cache_get_by_id ( $contextid )) {
$tofetch [] = $contextid ;
}
}
if ( count ( $tofetch ) > 1 ) {
// There are at least two to fetch.
// There is no point only fetching a single context as this would be no more efficient than calling the existing code.
list ( $insql , $inparams ) = $DB -> get_in_or_equal ( $tofetch , SQL_PARAMS_NAMED );
2019-01-09 19:05:22 +08:00
$ctxs = $DB -> get_records_select ( 'context' , " id { $insql } " , $inparams , '' ,
2018-10-17 13:36:39 +08:00
\context_helper :: get_preload_record_columns_sql ( '{context}' ));
foreach ( $ctxs as $ctx ) {
self :: preload_from_record ( $ctx );
}
}
}
2011-10-23 12:50:56 +02:00
/**
* Preload all contexts instances from course .
*
* To be used if you expect multiple queries for course activities ...
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param int $courseid
2011-10-23 12:50:56 +02:00
*/
public static function preload_course ( $courseid ) {
// Users can call this multiple times without doing any harm
if ( isset ( context :: $cache_preloaded [ $courseid ])) {
return ;
}
$coursecontext = context_course :: instance ( $courseid );
$coursecontext -> get_child_contexts ();
context :: $cache_preloaded [ $courseid ] = true ;
}
/**
* Delete context instance
*
* @ static
* @ param int $contextlevel
* @ param int $instanceid
* @ return void
*/
public static function delete_instance ( $contextlevel , $instanceid ) {
global $DB ;
// double check the context still exists
if ( $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => $contextlevel , 'instanceid' => $instanceid ))) {
$context = context :: create_instance_from_record ( $record );
$context -> delete ();
} else {
// we should try to purge the cache anyway
}
}
/**
* Returns the name of specified context level
*
* @ static
* @ param int $contextlevel
* @ return string name of the context level
*/
public static function get_level_name ( $contextlevel ) {
$classname = context_helper :: get_class_for_level ( $contextlevel );
return $classname :: get_level_name ();
}
2019-12-10 15:31:37 +00:00
/**
* Gets the current context to be used for navigation tree filtering .
*
* @ param context | null $context The current context to be checked against .
* @ return context | null the context that navigation tree filtering should use .
*/
public static function get_navigation_filter_context ( ? context $context ) : ? context {
global $CFG ;
if ( ! empty ( $CFG -> filternavigationwithsystemcontext )) {
return context_system :: instance ();
} else {
return $context ;
}
}
2011-10-23 12:50:56 +02:00
/**
* not used
*/
public function get_url () {
}
/**
* not used
2020-08-18 09:01:14 +01:00
*
* @ param string $sort
2011-10-23 12:50:56 +02:00
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-23 12:50:56 +02:00
}
}
2008-11-06 07:34:01 +00:00
/**
2012-01-14 19:12:43 +01:00
* System context class
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2008-11-06 07:34:01 +00:00
*/
2011-10-14 12:48:00 +02:00
class context_system extends context {
/**
* Please use context_system :: instance () if you need the instance of context .
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_SYSTEM ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_system constructor.' );
}
}
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'coresystem' );
2008-11-18 07:10:00 +00:00
}
2008-11-06 07:34:01 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix does not apply to system context
* @ param boolean $short does not apply to system context
2021-03-31 15:33:57 +02:00
* @ param boolean $escape does not apply to system context
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
return self :: get_level_name ();
2008-11-06 07:34:01 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
return new moodle_url ( '/' );
}
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2020-08-18 09:01:14 +01:00
return $DB -> get_records ( 'capabilities' , [], $sort );
2011-10-14 12:48:00 +02:00
}
/**
* Create missing context instances at system context
* @ static
*/
protected static function create_level_instances () {
// nothing to do here, the system context is created automatically in installer
self :: instance ( 0 );
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns system context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $instanceid should be 0
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ param bool $cache
* @ return context_system context instance
*/
public static function instance ( $instanceid = 0 , $strictness = MUST_EXIST , $cache = true ) {
global $DB ;
if ( $instanceid != 0 ) {
debugging ( 'context_system::instance(): invalid $id parameter detected, should be 0' );
}
2021-07-27 17:59:14 +10:00
// SYSCONTEXTID is cached in local cache to eliminate 1 query per page.
if ( defined ( 'SYSCONTEXTID' ) and $cache ) {
2011-10-14 12:48:00 +02:00
if ( ! isset ( context :: $systemcontext )) {
$record = new stdClass ();
$record -> id = SYSCONTEXTID ;
$record -> contextlevel = CONTEXT_SYSTEM ;
$record -> instanceid = 0 ;
$record -> path = '/' . SYSCONTEXTID ;
$record -> depth = 1 ;
2018-06-07 14:35:26 +08:00
$record -> locked = 0 ;
2011-10-14 12:48:00 +02:00
context :: $systemcontext = new context_system ( $record );
}
return context :: $systemcontext ;
}
try {
2013-07-03 14:51:56 +08:00
// We ignore the strictness completely because system context must exist except during install.
2011-10-14 12:48:00 +02:00
$record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_SYSTEM ), '*' , MUST_EXIST );
} catch ( dml_exception $e ) {
//table or record does not exist
if ( ! during_initial_install ()) {
// do not mess with system context after install, it simply must exist
throw $e ;
}
$record = null ;
}
if ( ! $record ) {
$record = new stdClass ();
$record -> contextlevel = CONTEXT_SYSTEM ;
$record -> instanceid = 0 ;
$record -> depth = 1 ;
2018-06-07 14:35:26 +08:00
$record -> path = null ; // Not known before insert.
$record -> locked = 0 ;
2011-10-14 12:48:00 +02:00
try {
if ( $DB -> count_records ( 'context' )) {
// contexts already exist, this is very weird, system must be first!!!
return null ;
}
if ( defined ( 'SYSCONTEXTID' )) {
// this would happen only in unittest on sites that went through weird 1.7 upgrade
$record -> id = SYSCONTEXTID ;
$DB -> import_record ( 'context' , $record );
$DB -> get_manager () -> reset_sequence ( 'context' );
} else {
$record -> id = $DB -> insert_record ( 'context' , $record );
}
} catch ( dml_exception $e ) {
// can not create context - table does not exist yet, sorry
return null ;
}
}
if ( $record -> instanceid != 0 ) {
// this is very weird, somebody must be messing with context table
debugging ( 'Invalid system context detected' );
}
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
if ( $record -> depth != 1 or $record -> path != '/' . $record -> id ) {
// fix path if necessary, initial install or path reset
$record -> depth = 1 ;
$record -> path = '/' . $record -> id ;
$DB -> update_record ( 'context' , $record );
}
2008-01-06 23:22:26 +00:00
2018-06-07 14:35:26 +08:00
if ( empty ( $record -> locked )) {
$record -> locked = 0 ;
}
2011-10-14 12:48:00 +02:00
if ( ! defined ( 'SYSCONTEXTID' )) {
define ( 'SYSCONTEXTID' , $record -> id );
2008-01-06 23:22:26 +00:00
}
2011-10-14 12:48:00 +02:00
context :: $systemcontext = new context_system ( $record );
return context :: $systemcontext ;
2008-01-06 23:22:26 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns all site contexts except the system context , DO NOT call on production servers !!
*
* Contexts are not cached .
*
* @ return array
*/
public function get_child_contexts () {
global $DB ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
debugging ( 'Fetching of system context child courses is strongly discouraged on production servers (it may eat all available memory)!' );
2007-09-27 01:46:41 +00:00
2011-10-14 12:48:00 +02:00
// Just get all the contexts except for CONTEXT_SYSTEM level
// and hope we don't OOM in the process - don't cache
$sql = " SELECT c.*
FROM { context } c
WHERE contextlevel > " .CONTEXT_SYSTEM;
$records = $DB -> get_records_sql ( $sql );
2008-01-06 23:22:26 +00:00
2011-10-14 12:48:00 +02:00
$result = array ();
foreach ( $records as $record ) {
$result [ $record -> id ] = context :: create_instance_from_record ( $record );
}
return $result ;
2008-01-06 23:23:58 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
WHERE 1 = 2
" ;
return $sql ;
2009-10-05 17:08:16 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at system context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
/* note: ignore $force here, we always do full test of system context */
// exactly one record must exist
$record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_SYSTEM ), '*' , MUST_EXIST );
if ( $record -> instanceid != 0 ) {
debugging ( 'Invalid system context detected' );
2007-06-26 16:16:46 +00:00
}
2011-10-14 12:48:00 +02:00
if ( defined ( 'SYSCONTEXTID' ) and $record -> id != SYSCONTEXTID ) {
debugging ( 'Invalid SYSCONTEXTID detected' );
2006-09-11 08:56:23 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $record -> depth != 1 or $record -> path != '/' . $record -> id ) {
// fix path if necessary, initial install or path reset
$record -> depth = 1 ;
$record -> path = '/' . $record -> id ;
$DB -> update_record ( 'context' , $record );
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
}
2018-06-07 14:35:26 +08:00
/**
* Set whether this context has been locked or not .
*
* @ param bool $locked
* @ return $this
*/
public function set_locked ( bool $locked ) {
throw new \coding_exception ( 'It is not possible to lock the system context' );
return $this ;
}
2011-10-14 12:48:00 +02:00
}
/**
* User context class
2012-01-14 19:12:43 +01:00
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-14 12:48:00 +02:00
*/
class context_user extends context {
/**
* Please use context_user :: instance ( $userid ) if you need the instance of context .
* Alternatively if you know only the context id use context :: instance_by_id ( $contextid )
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_USER ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_user constructor.' );
2008-05-25 10:16:53 +00:00
}
2008-01-06 23:22:26 +00:00
}
2008-01-06 23:22:08 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'user' );
2008-01-06 23:22:26 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with User
* @ param boolean $short does not apply to user context
2021-03-31 15:33:57 +02:00
* @ param boolean $escape does not apply to user context
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$name = '' ;
if ( $user = $DB -> get_record ( 'user' , array ( 'id' => $this -> _instanceid , 'deleted' => 0 ))) {
if ( $withprefix ){
$name = get_string ( 'user' ) . ': ' ;
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
$name .= fullname ( $user );
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
return $name ;
2006-09-16 13:54:57 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
global $COURSE ;
2006-09-16 13:54:57 +00:00
2011-10-14 12:48:00 +02:00
if ( $COURSE -> id == SITEID ) {
$url = new moodle_url ( '/user/profile.php' , array ( 'id' => $this -> _instanceid ));
2008-01-06 23:22:26 +00:00
} else {
2011-10-14 12:48:00 +02:00
$url = new moodle_url ( '/user/view.php' , array ( 'id' => $this -> _instanceid , 'courseid' => $COURSE -> id ));
2008-01-06 23:22:26 +00:00
}
2011-10-14 12:48:00 +02:00
return $url ;
2008-01-06 23:22:26 +00:00
}
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
$extracaps = array ( 'moodle/grade:viewall' );
list ( $extra , $params ) = $DB -> get_in_or_equal ( $extracaps , SQL_PARAMS_NAMED , 'cap' );
2020-08-18 09:01:14 +01:00
return $DB -> get_records_select ( 'capabilities' , " contextlevel = :level OR name { $extra } " ,
$params + [ 'level' => CONTEXT_USER ], $sort );
2008-01-06 23:22:26 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns user context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $userid id from { user } table
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ return context_user context instance
*/
2015-10-20 22:31:10 +03:00
public static function instance ( $userid , $strictness = MUST_EXIST ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2008-01-06 23:23:24 +00:00
2015-10-20 22:31:10 +03:00
if ( $context = context :: cache_get ( CONTEXT_USER , $userid )) {
2011-10-14 12:48:00 +02:00
return $context ;
}
2008-01-06 23:23:24 +00:00
2015-10-20 22:31:10 +03:00
if ( ! $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_USER , 'instanceid' => $userid ))) {
if ( $user = $DB -> get_record ( 'user' , array ( 'id' => $userid , 'deleted' => 0 ), 'id' , $strictness )) {
2011-10-14 12:48:00 +02:00
$record = context :: insert_context_record ( CONTEXT_USER , $user -> id , '/' . SYSCONTEXTID , 0 );
2011-07-04 18:50:21 +01:00
}
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
if ( $record ) {
$context = new context_user ( $record );
context :: cache_add ( $context );
return $context ;
}
return false ;
2008-05-24 18:35:48 +00:00
}
2008-01-06 23:23:24 +00:00
2011-10-14 12:48:00 +02:00
/**
* Create missing context instances at user context level
* @ static
*/
protected static function create_level_instances () {
global $DB ;
2015-02-23 14:25:21 +08:00
$sql = " SELECT " . CONTEXT_USER . " , u.id
2011-10-14 12:48:00 +02:00
FROM { user } u
WHERE u . deleted = 0
AND NOT EXISTS ( SELECT 'x'
FROM { context } cx
WHERE u . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_USER. " ) " ;
2015-02-23 16:01:36 +08:00
$contextdata = $DB -> get_recordset_sql ( $sql );
foreach ( $contextdata as $context ) {
context :: insert_context_record ( CONTEXT_USER , $context -> id , null );
2015-02-23 14:25:21 +08:00
}
2015-02-23 16:01:36 +08:00
$contextdata -> close ();
2010-03-07 09:28:54 +00:00
}
2008-01-06 23:23:24 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
LEFT OUTER JOIN { user } u ON ( c . instanceid = u . id AND u . deleted = 0 )
WHERE u . id IS NULL AND c . contextlevel = " .CONTEXT_USER. "
" ;
return $sql ;
}
/**
* Rebuild context paths and depths at user context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
2012-04-04 13:57:27 +01:00
// First update normal users.
$path = $DB -> sql_concat ( '?' , 'id' );
$pathstart = '/' . SYSCONTEXTID . '/' ;
$params = array ( $pathstart );
if ( $force ) {
$where = " depth <> 2 OR path IS NULL OR path <> ( { $path } ) " ;
$params [] = $pathstart ;
} else {
$where = " depth = 0 OR path IS NULL " ;
}
2011-10-14 12:48:00 +02:00
$sql = " UPDATE { context}
SET depth = 2 ,
2012-04-04 13:57:27 +01:00
path = { $path }
WHERE contextlevel = " . CONTEXT_USER . "
AND ( $where ) " ;
$DB -> execute ( $sql , $params );
2011-10-14 12:48:00 +02:00
}
}
/**
* Course category context class
2012-01-14 19:12:43 +01:00
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2011-10-14 12:48:00 +02:00
*/
class context_coursecat extends context {
/**
* Please use context_coursecat :: instance ( $coursecatid ) if you need the instance of context .
* Alternatively if you know only the context id use context :: instance_by_id ( $contextid )
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_COURSECAT ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_coursecat constructor.' );
2010-03-07 09:28:54 +00:00
}
2011-10-14 12:48:00 +02:00
}
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'category' );
}
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with Category
* @ param boolean $short does not apply to course categories
2021-03-31 15:33:57 +02:00
* @ param boolean $escape Whether the returned name of the context is to be HTML escaped or not .
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2010-10-26 07:51:09 +00:00
2011-10-14 12:48:00 +02:00
$name = '' ;
if ( $category = $DB -> get_record ( 'course_categories' , array ( 'id' => $this -> _instanceid ))) {
if ( $withprefix ){
$name = get_string ( 'category' ) . ': ' ;
}
2021-03-31 15:33:57 +02:00
if ( ! $escape ) {
$name .= format_string ( $category -> name , true , array ( 'context' => $this , 'escape' => false ));
} else {
$name .= format_string ( $category -> name , true , array ( 'context' => $this ));
}
2011-10-14 12:48:00 +02:00
}
return $name ;
}
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
2013-04-09 12:21:05 +10:00
return new moodle_url ( '/course/index.php' , array ( 'categoryid' => $this -> _instanceid ));
2011-10-14 12:48:00 +02:00
}
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2020-08-18 09:01:14 +01:00
return $DB -> get_records_list ( 'capabilities' , 'contextlevel' , [
CONTEXT_COURSECAT ,
CONTEXT_COURSE ,
CONTEXT_MODULE ,
CONTEXT_BLOCK ,
], $sort );
2011-10-14 12:48:00 +02:00
}
/**
* Returns course category context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $categoryid id from { course_categories } table
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ return context_coursecat context instance
*/
2015-10-20 22:31:10 +03:00
public static function instance ( $categoryid , $strictness = MUST_EXIST ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2015-10-20 22:31:10 +03:00
if ( $context = context :: cache_get ( CONTEXT_COURSECAT , $categoryid )) {
2011-10-14 12:48:00 +02:00
return $context ;
}
2010-03-07 09:28:54 +00:00
2015-10-20 22:31:10 +03:00
if ( ! $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_COURSECAT , 'instanceid' => $categoryid ))) {
if ( $category = $DB -> get_record ( 'course_categories' , array ( 'id' => $categoryid ), 'id,parent' , $strictness )) {
2011-10-14 12:48:00 +02:00
if ( $category -> parent ) {
$parentcontext = context_coursecat :: instance ( $category -> parent );
$record = context :: insert_context_record ( CONTEXT_COURSECAT , $category -> id , $parentcontext -> path );
2008-01-06 23:23:58 +00:00
} else {
2011-10-14 12:48:00 +02:00
$record = context :: insert_context_record ( CONTEXT_COURSECAT , $category -> id , '/' . SYSCONTEXTID , 0 );
2008-01-06 23:23:58 +00:00
}
}
}
2011-10-14 12:48:00 +02:00
if ( $record ) {
$context = new context_coursecat ( $record );
context :: cache_add ( $context );
return $context ;
2008-01-06 23:24:25 +00:00
}
2008-01-06 23:23:58 +00:00
2011-10-14 12:48:00 +02:00
return false ;
2010-03-07 09:28:54 +00:00
}
2008-01-06 23:24:25 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns immediate child contexts of category and all subcategories ,
* children of subcategories and courses are not returned .
*
* @ return array
*/
public function get_child_contexts () {
global $DB ;
2008-01-06 23:24:25 +00:00
2013-12-16 09:44:04 +08:00
if ( empty ( $this -> _path ) or empty ( $this -> _depth )) {
debugging ( 'Can not find child contexts of context ' . $this -> _id . ' try rebuilding of context paths' );
return array ();
}
2011-10-14 12:48:00 +02:00
$sql = " SELECT ctx.*
FROM { context } ctx
WHERE ctx . path LIKE ? AND ( ctx . depth = ? OR ctx . contextlevel = ? ) " ;
$params = array ( $this -> _path . '/%' , $this -> depth + 1 , CONTEXT_COURSECAT );
$records = $DB -> get_records_sql ( $sql , $params );
2006-09-03 07:56:40 +00:00
2011-10-14 12:48:00 +02:00
$result = array ();
foreach ( $records as $record ) {
$result [ $record -> id ] = context :: create_instance_from_record ( $record );
}
2008-01-06 23:25:37 +00:00
2011-10-14 12:48:00 +02:00
return $result ;
2008-01-06 23:25:37 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Create missing context instances at course category context level
* @ static
*/
protected static function create_level_instances () {
global $DB ;
2008-01-06 23:25:37 +00:00
2015-02-23 14:25:21 +08:00
$sql = " SELECT " . CONTEXT_COURSECAT . " , cc.id
2011-10-14 12:48:00 +02:00
FROM { course_categories } cc
WHERE NOT EXISTS ( SELECT 'x'
FROM { context } cx
WHERE cc . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSECAT. " ) " ;
2015-02-23 16:01:36 +08:00
$contextdata = $DB -> get_recordset_sql ( $sql );
foreach ( $contextdata as $context ) {
context :: insert_context_record ( CONTEXT_COURSECAT , $context -> id , null );
2015-02-23 14:25:21 +08:00
}
2015-02-23 16:01:36 +08:00
$contextdata -> close ();
2008-01-06 23:25:37 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
LEFT OUTER JOIN { course_categories } cc ON c . instanceid = cc . id
WHERE cc . id IS NULL AND c . contextlevel = " .CONTEXT_COURSECAT. "
" ;
2008-01-06 23:25:37 +00:00
2011-10-14 12:48:00 +02:00
return $sql ;
}
2008-01-06 23:25:37 +00:00
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at course category context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
if ( $force or $DB -> record_exists_select ( 'context' , " contextlevel = " . CONTEXT_COURSECAT . " AND (depth = 0 OR path IS NULL) " )) {
if ( $force ) {
$ctxemptyclause = $emptyclause = '' ;
} else {
$ctxemptyclause = " AND (ctx.path IS NULL OR ctx.depth = 0) " ;
$emptyclause = " AND ( { context}.path IS NULL OR { context}.depth = 0) " ;
}
$base = '/' . SYSCONTEXTID ;
// Normal top level categories
$sql = " UPDATE { context}
SET depth = 2 ,
path = " . $DB->sql_concat ( " '$base/' " , 'id'). "
WHERE contextlevel = " .CONTEXT_COURSECAT. "
AND EXISTS ( SELECT 'x'
FROM { course_categories } cc
WHERE cc . id = { context } . instanceid AND cc . depth = 1 )
$emptyclause " ;
$DB -> execute ( $sql );
// Deeper categories - one query per depthlevel
$maxdepth = $DB -> get_field_sql ( " SELECT MAX(depth) FROM { course_categories} " );
for ( $n = 2 ; $n <= $maxdepth ; $n ++ ) {
2018-06-07 14:35:26 +08:00
$sql = " INSERT INTO { context_temp} (id, path, depth, locked)
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1 , ctx . locked
2011-10-14 12:48:00 +02:00
FROM { context } ctx
JOIN { course_categories } cc ON ( cc . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSECAT. " AND cc . depth = $n )
JOIN { context } pctx ON ( pctx . instanceid = cc . parent AND pctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE pctx . path IS NOT NULL AND pctx . depth > 0
$ctxemptyclause " ;
$trans = $DB -> start_delegated_transaction ();
$DB -> delete_records ( 'context_temp' );
$DB -> execute ( $sql );
context :: merge_context_temp_table ();
$DB -> delete_records ( 'context_temp' );
$trans -> allow_commit ();
}
}
2008-01-06 23:25:37 +00:00
}
}
2011-10-14 12:48:00 +02:00
2006-09-12 07:37:23 +00:00
/**
2011-10-14 12:48:00 +02:00
* Course context class
2012-01-14 19:12:43 +01:00
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2006-09-12 07:37:23 +00:00
*/
2011-10-14 12:48:00 +02:00
class context_course extends context {
/**
* Please use context_course :: instance ( $courseid ) if you need the instance of context .
* Alternatively if you know only the context id use context :: instance_by_id ( $contextid )
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_COURSE ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_course constructor.' );
}
}
2006-09-20 21:00:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'course' );
2006-10-25 07:20:28 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with Course
* @ param boolean $short whether to use the short name of the thing .
2021-03-31 15:33:57 +02:00
* @ param bool $escape Whether the returned category name is to be HTML escaped or not .
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$name = '' ;
if ( $this -> _instanceid == SITEID ) {
$name = get_string ( 'frontpage' , 'admin' );
} else {
if ( $course = $DB -> get_record ( 'course' , array ( 'id' => $this -> _instanceid ))) {
if ( $withprefix ){
$name = get_string ( 'course' ) . ': ' ;
}
if ( $short ){
2021-03-31 15:33:57 +02:00
if ( ! $escape ) {
$name .= format_string ( $course -> shortname , true , array ( 'context' => $this , 'escape' => false ));
} else {
$name .= format_string ( $course -> shortname , true , array ( 'context' => $this ));
}
2011-10-14 12:48:00 +02:00
} else {
2021-03-31 15:33:57 +02:00
if ( ! $escape ) {
$name .= format_string ( get_course_display_name_for_list ( $course ), true , array ( 'context' => $this ,
'escape' => false ));
} else {
$name .= format_string ( get_course_display_name_for_list ( $course ), true , array ( 'context' => $this ));
}
2021-03-31 15:33:57 +02:00
}
2011-10-14 12:48:00 +02:00
}
2006-09-12 07:37:23 +00:00
}
2011-10-14 12:48:00 +02:00
return $name ;
2006-09-20 21:00:45 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
if ( $this -> _instanceid != SITEID ) {
return new moodle_url ( '/course/view.php' , array ( 'id' => $this -> _instanceid ));
}
return new moodle_url ( '/' );
}
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2020-08-18 09:01:14 +01:00
return $DB -> get_records_list ( 'capabilities' , 'contextlevel' , [
CONTEXT_COURSE ,
CONTEXT_MODULE ,
CONTEXT_BLOCK ,
], $sort );
2006-10-01 08:34:36 +00:00
}
2007-09-13 13:44:35 +00:00
2011-10-14 12:48:00 +02:00
/**
* Is this context part of any course ? If yes return course context .
*
* @ param bool $strict true means throw exception if not found , false means return false if not found
2014-04-15 15:46:19 +08:00
* @ return context_course context of the enclosing course , null if not found or exception
2011-10-14 12:48:00 +02:00
*/
public function get_course_context ( $strict = true ) {
return $this ;
}
/**
* Returns course context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $courseid id from { course } table
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ return context_course context instance
*/
2015-10-20 22:31:10 +03:00
public static function instance ( $courseid , $strictness = MUST_EXIST ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2015-10-20 22:31:10 +03:00
if ( $context = context :: cache_get ( CONTEXT_COURSE , $courseid )) {
2011-10-14 12:48:00 +02:00
return $context ;
}
2015-10-20 22:31:10 +03:00
if ( ! $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_COURSE , 'instanceid' => $courseid ))) {
if ( $course = $DB -> get_record ( 'course' , array ( 'id' => $courseid ), 'id,category' , $strictness )) {
2011-10-14 12:48:00 +02:00
if ( $course -> category ) {
$parentcontext = context_coursecat :: instance ( $course -> category );
$record = context :: insert_context_record ( CONTEXT_COURSE , $course -> id , $parentcontext -> path );
} else {
$record = context :: insert_context_record ( CONTEXT_COURSE , $course -> id , '/' . SYSCONTEXTID , 0 );
}
}
}
if ( $record ) {
$context = new context_course ( $record );
context :: cache_add ( $context );
return $context ;
}
return false ;
}
/**
* Create missing context instances at course context level
* @ static
*/
protected static function create_level_instances () {
global $DB ;
2015-02-23 14:25:21 +08:00
$sql = " SELECT " . CONTEXT_COURSE . " , c.id
2011-10-14 12:48:00 +02:00
FROM { course } c
WHERE NOT EXISTS ( SELECT 'x'
FROM { context } cx
WHERE c . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSE. " ) " ;
2015-02-23 16:01:36 +08:00
$contextdata = $DB -> get_recordset_sql ( $sql );
foreach ( $contextdata as $context ) {
context :: insert_context_record ( CONTEXT_COURSE , $context -> id , null );
2015-02-23 14:25:21 +08:00
}
2015-02-23 16:01:36 +08:00
$contextdata -> close ();
2007-07-09 06:22:56 +00:00
}
2006-10-01 08:34:36 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
LEFT OUTER JOIN { course } co ON c . instanceid = co . id
WHERE co . id IS NULL AND c . contextlevel = " .CONTEXT_COURSE. "
" ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
return $sql ;
2008-10-30 10:49:15 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at course context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
if ( $force or $DB -> record_exists_select ( 'context' , " contextlevel = " . CONTEXT_COURSE . " AND (depth = 0 OR path IS NULL) " )) {
if ( $force ) {
$ctxemptyclause = $emptyclause = '' ;
} else {
$ctxemptyclause = " AND (ctx.path IS NULL OR ctx.depth = 0) " ;
$emptyclause = " AND ( { context}.path IS NULL OR { context}.depth = 0) " ;
}
$base = '/' . SYSCONTEXTID ;
// Standard frontpage
$sql = " UPDATE { context}
SET depth = 2 ,
path = " . $DB->sql_concat ( " '$base/' " , 'id'). "
WHERE contextlevel = " .CONTEXT_COURSE. "
AND EXISTS ( SELECT 'x'
FROM { course } c
WHERE c . id = { context } . instanceid AND c . category = 0 )
$emptyclause " ;
$DB -> execute ( $sql );
// standard courses
2018-06-07 14:35:26 +08:00
$sql = " INSERT INTO { context_temp} (id, path, depth, locked)
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1 , ctx . locked
2011-10-14 12:48:00 +02:00
FROM { context } ctx
JOIN { course } c ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " AND c . category <> 0 )
JOIN { context } pctx ON ( pctx . instanceid = c . category AND pctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE pctx . path IS NOT NULL AND pctx . depth > 0
$ctxemptyclause " ;
$trans = $DB -> start_delegated_transaction ();
$DB -> delete_records ( 'context_temp' );
$DB -> execute ( $sql );
context :: merge_context_temp_table ();
$DB -> delete_records ( 'context_temp' );
$trans -> allow_commit ();
}
}
2006-09-12 07:37:23 +00:00
}
2011-10-14 12:48:00 +02:00
2006-09-28 04:42:49 +00:00
/**
2011-10-14 12:48:00 +02:00
* Course module context class
2012-01-14 19:12:43 +01:00
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2006-09-28 04:42:49 +00:00
*/
2011-10-14 12:48:00 +02:00
class context_module extends context {
/**
* Please use context_module :: instance ( $cmid ) if you need the instance of context .
* Alternatively if you know only the context id use context :: instance_by_id ( $contextid )
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_MODULE ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_module constructor.' );
2006-09-28 04:42:49 +00:00
}
}
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'activitymodule' );
2008-12-19 08:45:44 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with the
* module name , e . g . Forum , Glossary , etc .
* @ param boolean $short does not apply to module context
2021-03-31 15:33:57 +02:00
* @ param boolean $escape Whether the returned name of the context is to be HTML escaped or not .
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
global $DB ;
$name = '' ;
if ( $cm = $DB -> get_record_sql ( " SELECT cm.*, md.name AS modname
FROM { course_modules } cm
JOIN { modules } md ON md . id = cm . module
WHERE cm . id = ? " , array( $this->_instanceid ))) {
if ( $mod = $DB -> get_record ( $cm -> modname , array ( 'id' => $cm -> instance ))) {
if ( $withprefix ){
$name = get_string ( 'modulename' , $cm -> modname ) . ': ' ;
}
2021-03-31 15:33:57 +02:00
if ( ! $escape ) {
$name .= format_string ( $mod -> name , true , array ( 'context' => $this , 'escape' => false ));
} else {
$name .= format_string ( $mod -> name , true , array ( 'context' => $this ));
}
2011-10-14 12:48:00 +02:00
}
}
return $name ;
}
2008-12-19 08:45:44 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
global $DB ;
2006-09-28 04:42:49 +00:00
2011-10-14 12:48:00 +02:00
if ( $modname = $DB -> get_field_sql ( " SELECT md.name AS modname
FROM { course_modules } cm
JOIN { modules } md ON md . id = cm . module
WHERE cm . id = ? " , array( $this->_instanceid ))) {
return new moodle_url ( '/mod/' . $modname . '/view.php' , array ( 'id' => $this -> _instanceid ));
}
2006-09-28 04:42:49 +00:00
2011-10-14 12:48:00 +02:00
return new moodle_url ( '/' );
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB , $CFG ;
$cm = $DB -> get_record ( 'course_modules' , array ( 'id' => $this -> _instanceid ));
$module = $DB -> get_record ( 'modules' , array ( 'id' => $cm -> module ));
$subcaps = array ();
2019-02-12 22:03:12 +08:00
$modulepath = " { $CFG -> dirroot } /mod/ { $module -> name } " ;
if ( file_exists ( " { $modulepath } /db/subplugins.json " )) {
$subplugins = ( array ) json_decode ( file_get_contents ( " { $modulepath } /db/subplugins.json " )) -> plugintypes ;
} else if ( file_exists ( " { $modulepath } /db/subplugins.php " )) {
debugging ( 'Use of subplugins.php has been deprecated. ' .
'Please update your plugin to provide a subplugins.json file instead.' ,
DEBUG_DEVELOPER );
2011-10-14 12:48:00 +02:00
$subplugins = array (); // should be redefined in the file
2019-02-12 22:03:12 +08:00
include ( " { $modulepath } /db/subplugins.php " );
}
if ( ! empty ( $subplugins )) {
foreach ( array_keys ( $subplugins ) as $subplugintype ) {
foreach ( array_keys ( core_component :: get_plugin_list ( $subplugintype )) as $subpluginname ) {
$subcaps = array_merge ( $subcaps , array_keys ( load_capability_def ( $subplugintype . '_' . $subpluginname )));
2011-10-14 12:48:00 +02:00
}
}
2007-05-14 12:11:47 +00:00
}
2011-10-14 12:48:00 +02:00
2019-02-12 22:03:12 +08:00
$modfile = " { $modulepath } /lib.php " ;
2012-01-25 15:21:37 +13:00
$extracaps = array ();
2011-10-14 12:48:00 +02:00
if ( file_exists ( $modfile )) {
include_once ( $modfile );
$modfunction = $module -> name . '_get_extra_capabilities' ;
if ( function_exists ( $modfunction )) {
$extracaps = $modfunction ();
2007-05-14 12:11:47 +00:00
}
}
2007-09-13 13:44:35 +00:00
2011-10-14 12:48:00 +02:00
$extracaps = array_merge ( $subcaps , $extracaps );
2012-01-25 15:21:37 +13:00
$extra = '' ;
2012-02-01 23:09:49 +13:00
list ( $extra , $params ) = $DB -> get_in_or_equal (
$extracaps , SQL_PARAMS_NAMED , 'cap0' , true , '' );
if ( ! empty ( $extra )) {
2012-01-25 15:21:37 +13:00
$extra = " OR name $extra " ;
}
2018-11-01 08:22:48 +08:00
// Fetch the list of modules, and remove this one.
$components = \core_component :: get_component_list ();
$componentnames = $components [ 'mod' ];
unset ( $componentnames [ " mod_ { $module -> name } " ]);
$componentnames = array_keys ( $componentnames );
// Exclude all other modules.
list ( $notcompsql , $notcompparams ) = $DB -> get_in_or_equal ( $componentnames , SQL_PARAMS_NAMED , 'notcomp' , false );
$params = array_merge ( $params , $notcompparams );
// Exclude other component submodules.
$i = 0 ;
$ignorecomponents = [];
foreach ( $componentnames as $mod ) {
if ( $subplugins = \core_component :: get_subplugins ( $mod )) {
foreach ( array_keys ( $subplugins ) as $subplugintype ) {
$paramname = " notlike { $i } " ;
$ignorecomponents [] = $DB -> sql_like ( 'component' , " : { $paramname } " , true , true , true );
$params [ $paramname ] = " { $subplugintype } _% " ;
$i ++ ;
}
}
}
$notlikesql = " ( " . implode ( ' AND ' , $ignorecomponents ) . " ) " ;
2011-10-14 12:48:00 +02:00
$sql = " SELECT *
FROM { capabilities }
WHERE ( contextlevel = " .CONTEXT_MODULE. "
2018-11-01 08:22:48 +08:00
AND component { $notcompsql }
AND { $notlikesql })
2020-08-18 09:01:14 +01:00
$extra
ORDER BY $sort " ;
2011-10-14 12:48:00 +02:00
2020-08-18 09:01:14 +01:00
return $DB -> get_records_sql ( $sql , $params );
2006-09-19 01:44:33 +00:00
}
2006-09-21 03:21:33 +00:00
2011-10-14 12:48:00 +02:00
/**
* Is this context part of any course ? If yes return course context .
*
* @ param bool $strict true means throw exception if not found , false means return false if not found
2013-07-06 14:35:02 +02:00
* @ return context_course context of the enclosing course , null if not found or exception
2011-10-14 12:48:00 +02:00
*/
public function get_course_context ( $strict = true ) {
return $this -> get_parent_context ();
}
2006-09-21 22:34:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns module context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $cmid id of the record from { course_modules } table ; pass cmid there , NOT id in the instance column
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ return context_module context instance
*/
2015-10-20 22:31:10 +03:00
public static function instance ( $cmid , $strictness = MUST_EXIST ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2006-09-21 22:34:45 +00:00
2015-10-20 22:31:10 +03:00
if ( $context = context :: cache_get ( CONTEXT_MODULE , $cmid )) {
2011-10-14 12:48:00 +02:00
return $context ;
}
2006-09-21 06:57:14 +00:00
2015-10-20 22:31:10 +03:00
if ( ! $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_MODULE , 'instanceid' => $cmid ))) {
if ( $cm = $DB -> get_record ( 'course_modules' , array ( 'id' => $cmid ), 'id,course' , $strictness )) {
2011-10-14 12:48:00 +02:00
$parentcontext = context_course :: instance ( $cm -> course );
$record = context :: insert_context_record ( CONTEXT_MODULE , $cm -> id , $parentcontext -> path );
}
}
2006-09-21 09:16:41 +00:00
2011-10-14 12:48:00 +02:00
if ( $record ) {
$context = new context_module ( $record );
context :: cache_add ( $context );
return $context ;
}
2006-09-21 09:16:41 +00:00
2011-10-14 12:48:00 +02:00
return false ;
2007-09-19 07:11:18 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Create missing context instances at module context level
* @ static
*/
protected static function create_level_instances () {
global $DB ;
2015-02-23 14:25:21 +08:00
$sql = " SELECT " . CONTEXT_MODULE . " , cm.id
2011-10-14 12:48:00 +02:00
FROM { course_modules } cm
WHERE NOT EXISTS ( SELECT 'x'
FROM { context } cx
WHERE cm . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_MODULE. " ) " ;
2015-02-23 16:01:36 +08:00
$contextdata = $DB -> get_recordset_sql ( $sql );
foreach ( $contextdata as $context ) {
context :: insert_context_record ( CONTEXT_MODULE , $context -> id , null );
2015-02-23 14:25:21 +08:00
}
2015-02-23 16:01:36 +08:00
$contextdata -> close ();
2007-09-19 07:06:03 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
LEFT OUTER JOIN { course_modules } cm ON c . instanceid = cm . id
WHERE cm . id IS NULL AND c . contextlevel = " .CONTEXT_MODULE. "
" ;
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
return $sql ;
}
2006-09-21 09:16:41 +00:00
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at module context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
2006-09-21 09:16:41 +00:00
2011-10-14 12:48:00 +02:00
if ( $force or $DB -> record_exists_select ( 'context' , " contextlevel = " . CONTEXT_MODULE . " AND (depth = 0 OR path IS NULL) " )) {
if ( $force ) {
$ctxemptyclause = '' ;
} else {
$ctxemptyclause = " AND (ctx.path IS NULL OR ctx.depth = 0) " ;
}
2018-06-07 14:35:26 +08:00
$sql = " INSERT INTO { context_temp} (id, path, depth, locked)
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1 , ctx . locked
2011-10-14 12:48:00 +02:00
FROM { context } ctx
JOIN { course_modules } cm ON ( cm . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_MODULE. " )
JOIN { context } pctx ON ( pctx . instanceid = cm . course AND pctx . contextlevel = " .CONTEXT_COURSE. " )
WHERE pctx . path IS NOT NULL AND pctx . depth > 0
$ctxemptyclause " ;
$trans = $DB -> start_delegated_transaction ();
$DB -> delete_records ( 'context_temp' );
$DB -> execute ( $sql );
context :: merge_context_temp_table ();
$DB -> delete_records ( 'context_temp' );
$trans -> allow_commit ();
}
}
2010-08-27 01:44:25 +00:00
}
2006-09-21 09:16:41 +00:00
2011-10-14 12:48:00 +02:00
2008-05-24 18:35:48 +00:00
/**
2011-10-14 12:48:00 +02:00
* Block context class
2012-01-14 19:12:43 +01:00
*
* @ package core_access
* @ category access
* @ copyright Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2014-05-19 17:03:04 +01:00
* @ since Moodle 2.2
2008-05-24 18:35:48 +00:00
*/
2011-10-14 12:48:00 +02:00
class context_block extends context {
/**
* Please use context_block :: instance ( $blockinstanceid ) if you need the instance of context .
* Alternatively if you know only the context id use context :: instance_by_id ( $contextid )
*
* @ param stdClass $record
*/
protected function __construct ( stdClass $record ) {
parent :: __construct ( $record );
if ( $record -> contextlevel != CONTEXT_BLOCK ) {
throw new coding_exception ( 'Invalid $record->contextlevel in context_block constructor' );
}
}
2006-09-21 22:34:45 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context level name .
*
* @ static
* @ return string the human readable context level name .
*/
2012-01-08 15:39:03 +01:00
public static function get_level_name () {
2011-10-14 12:48:00 +02:00
return get_string ( 'block' );
}
2006-09-21 06:57:14 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns human readable context identifier .
*
* @ param boolean $withprefix whether to prefix the name of the context with Block
* @ param boolean $short does not apply to block context
2021-03-31 15:33:57 +02:00
* @ param boolean $escape does not apply to block context
2011-10-14 12:48:00 +02:00
* @ return string the human readable context name .
*/
2021-03-31 15:33:57 +02:00
public function get_context_name ( $withprefix = true , $short = false , $escape = true ) {
2011-10-14 12:48:00 +02:00
global $DB , $CFG ;
$name = '' ;
if ( $blockinstance = $DB -> get_record ( 'block_instances' , array ( 'id' => $this -> _instanceid ))) {
global $CFG ;
require_once ( " $CFG->dirroot /blocks/moodleblock.class.php " );
require_once ( " $CFG->dirroot /blocks/ $blockinstance->blockname /block_ $blockinstance->blockname .php " );
$blockname = " block_ $blockinstance->blockname " ;
if ( $blockobject = new $blockname ()) {
if ( $withprefix ){
$name = get_string ( 'block' ) . ': ' ;
}
$name .= $blockobject -> title ;
}
}
2006-09-21 22:34:45 +00:00
2011-10-14 12:48:00 +02:00
return $name ;
}
2006-09-21 09:09:16 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns the most relevant URL for this context .
*
* @ return moodle_url
*/
public function get_url () {
$parentcontexts = $this -> get_parent_context ();
return $parentcontexts -> get_url ();
}
2006-09-23 12:51:00 +00:00
2011-10-14 12:48:00 +02:00
/**
* Returns array of relevant context capability records .
*
2020-08-18 09:01:14 +01:00
* @ param string $sort
2011-10-14 12:48:00 +02:00
* @ return array
*/
2020-08-18 09:01:14 +01:00
public function get_capabilities ( string $sort = self :: DEFAULT_CAPABILITY_SORT ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2006-09-22 01:46:45 +00:00
2011-10-14 12:48:00 +02:00
$bi = $DB -> get_record ( 'block_instances' , array ( 'id' => $this -> _instanceid ));
2006-09-22 01:46:45 +00:00
2020-08-18 09:01:14 +01:00
$select = '(contextlevel = :level AND component = :component)' ;
$params = [
'level' => CONTEXT_BLOCK ,
'component' => 'block_' . $bi -> blockname ,
];
2011-10-14 12:48:00 +02:00
$extracaps = block_method_result ( $bi -> blockname , 'get_extra_capabilities' );
if ( $extracaps ) {
2020-08-18 09:01:14 +01:00
list ( $extra , $extraparams ) = $DB -> get_in_or_equal ( $extracaps , SQL_PARAMS_NAMED , 'cap' );
$select .= " OR name $extra " ;
$params = array_merge ( $params , $extraparams );
2011-10-14 12:48:00 +02:00
}
2006-09-21 22:34:45 +00:00
2020-08-18 09:01:14 +01:00
return $DB -> get_records_select ( 'capabilities' , $select , $params , $sort );
2011-10-14 12:48:00 +02:00
}
2006-10-04 07:07:57 +00:00
2011-10-14 12:48:00 +02:00
/**
* Is this context part of any course ? If yes return course context .
*
* @ param bool $strict true means throw exception if not found , false means return false if not found
2014-04-15 15:46:19 +08:00
* @ return context_course context of the enclosing course , null if not found or exception
2011-10-14 12:48:00 +02:00
*/
public function get_course_context ( $strict = true ) {
$parentcontext = $this -> get_parent_context ();
return $parentcontext -> get_course_context ( $strict );
}
/**
* Returns block context instance .
*
* @ static
2015-10-20 22:31:10 +03:00
* @ param int $blockinstanceid id from { block_instances } table .
2011-10-14 12:48:00 +02:00
* @ param int $strictness
* @ return context_block context instance
*/
2015-10-20 22:31:10 +03:00
public static function instance ( $blockinstanceid , $strictness = MUST_EXIST ) {
2011-10-14 12:48:00 +02:00
global $DB ;
2015-10-20 22:31:10 +03:00
if ( $context = context :: cache_get ( CONTEXT_BLOCK , $blockinstanceid )) {
2011-10-14 12:48:00 +02:00
return $context ;
2011-01-30 21:49:22 +01:00
}
2015-10-20 22:31:10 +03:00
if ( ! $record = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_BLOCK , 'instanceid' => $blockinstanceid ))) {
if ( $bi = $DB -> get_record ( 'block_instances' , array ( 'id' => $blockinstanceid ), 'id,parentcontextid' , $strictness )) {
2011-10-14 12:48:00 +02:00
$parentcontext = context :: instance_by_id ( $bi -> parentcontextid );
$record = context :: insert_context_record ( CONTEXT_BLOCK , $bi -> id , $parentcontext -> path );
}
}
2011-01-30 21:49:22 +01:00
2011-10-14 12:48:00 +02:00
if ( $record ) {
$context = new context_block ( $record );
context :: cache_add ( $context );
return $context ;
}
2011-01-30 21:49:22 +01:00
2011-10-14 12:48:00 +02:00
return false ;
2006-10-04 07:07:57 +00:00
}
2007-01-12 07:41:33 +00:00
2011-10-14 12:48:00 +02:00
/**
* Block do not have child contexts ...
* @ return array
*/
public function get_child_contexts () {
return array ();
}
2008-05-24 18:35:48 +00:00
2011-10-14 12:48:00 +02:00
/**
* Create missing context instances at block context level
* @ static
*/
protected static function create_level_instances () {
global $DB ;
2022-04-06 13:41:23 +08:00
$sql = <<< EOF
INSERT INTO { context } (
contextlevel ,
instanceid
) SELECT
: contextlevel ,
bi . id as instanceid
FROM { block_instances } bi
WHERE NOT EXISTS (
SELECT 'x' FROM { context } cx WHERE bi . id = cx . instanceid AND cx . contextlevel = : existingcontextlevel
)
EOF ;
$DB -> execute ( $sql , [
'contextlevel' => CONTEXT_BLOCK ,
'existingcontextlevel' => CONTEXT_BLOCK ,
]);
2008-02-21 09:20:20 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Returns sql necessary for purging of stale context instances .
*
* @ static
* @ return string cleanup SQL
*/
protected static function get_cleanup_sql () {
$sql = "
SELECT c .*
FROM { context } c
LEFT OUTER JOIN { block_instances } bi ON c . instanceid = bi . id
WHERE bi . id IS NULL AND c . contextlevel = " .CONTEXT_BLOCK. "
" ;
2008-11-13 08:11:10 +00:00
2011-10-14 12:48:00 +02:00
return $sql ;
2008-11-13 08:11:10 +00:00
}
2011-10-14 12:48:00 +02:00
/**
* Rebuild context paths and depths at block context level .
*
* @ static
2012-02-21 11:48:33 +13:00
* @ param bool $force
2011-10-14 12:48:00 +02:00
*/
protected static function build_paths ( $force ) {
global $DB ;
2008-11-13 08:11:10 +00:00
2011-10-14 12:48:00 +02:00
if ( $force or $DB -> record_exists_select ( 'context' , " contextlevel = " . CONTEXT_BLOCK . " AND (depth = 0 OR path IS NULL) " )) {
if ( $force ) {
$ctxemptyclause = '' ;
} else {
$ctxemptyclause = " AND (ctx.path IS NULL OR ctx.depth = 0) " ;
2008-02-21 09:20:20 +00:00
}
2008-11-13 08:11:10 +00:00
2011-10-14 12:48:00 +02:00
// pctx.path IS NOT NULL prevents fatal problems with broken block instances that point to invalid context parent
2018-06-07 14:35:26 +08:00
$sql = " INSERT INTO { context_temp} (id, path, depth, locked)
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1 , ctx . locked
2011-10-14 12:48:00 +02:00
FROM { context } ctx
JOIN { block_instances } bi ON ( bi . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_BLOCK. " )
JOIN { context } pctx ON ( pctx . id = bi . parentcontextid )
WHERE ( pctx . path IS NOT NULL AND pctx . depth > 0 )
$ctxemptyclause " ;
$trans = $DB -> start_delegated_transaction ();
$DB -> delete_records ( 'context_temp' );
$DB -> execute ( $sql );
context :: merge_context_temp_table ();
$DB -> delete_records ( 'context_temp' );
$trans -> allow_commit ();
2008-11-13 08:11:10 +00:00
}
2007-03-22 08:11:30 +00:00
}
}
2007-08-02 08:28:29 +00:00
2011-10-14 12:48:00 +02:00
2011-10-25 14:20:22 +02:00
// ============== DEPRECATED FUNCTIONS ==========================================
// Old context related functions were deprecated in 2.0, it is recommended
// to use context classes in new code. Old function can be used when
// creating patches that are supposed to be backported to older stable branches.
// These deprecated functions will not be removed in near future,
// before removing devs will be warned with a debugging message first,
// then we will add error message and only after that we can remove the functions
// completely.
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
2011-10-14 12:48:00 +02:00
/**
* Runs get_records select on context table and returns the result
* Does get_records_select on the context table , and returns the results ordered
* by contextlevel , and then the natural sort order within each level .
* for the purpose of $select , you need to know that the context table has been
* aliased to ctx , so for example , you can call get_sorted_contexts ( 'ctx.depth = 3' );
*
* @ param string $select the contents of the WHERE clause . Remember to do ctx . fieldname .
* @ param array $params any parameters required by $select .
* @ return array the requested context records .
*/
function get_sorted_contexts ( $select , $params = array ()) {
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
//TODO: we should probably rewrite all the code that is using this thing, the trouble is we MUST NOT modify the context instances...
2010-03-07 09:28:54 +00:00
2011-10-14 12:48:00 +02:00
global $DB ;
if ( $select ) {
$select = 'WHERE ' . $select ;
}
return $DB -> get_records_sql ( "
SELECT ctx .*
FROM { context } ctx
LEFT JOIN { user } u ON ctx . contextlevel = " . CONTEXT_USER . " AND u . id = ctx . instanceid
LEFT JOIN { course_categories } cat ON ctx . contextlevel = " . CONTEXT_COURSECAT . " AND cat . id = ctx . instanceid
LEFT JOIN { course } c ON ctx . contextlevel = " . CONTEXT_COURSE . " AND c . id = ctx . instanceid
LEFT JOIN { course_modules } cm ON ctx . contextlevel = " . CONTEXT_MODULE . " AND cm . id = ctx . instanceid
LEFT JOIN { block_instances } bi ON ctx . contextlevel = " . CONTEXT_BLOCK . " AND bi . id = ctx . instanceid
$select
ORDER BY ctx . contextlevel , bi . defaultregion , COALESCE ( cat . sortorder , c . sortorder , cm . section , bi . defaultweight ), u . lastname , u . firstname , cm . id
" , $params );
2010-03-07 09:28:54 +00:00
}
2013-03-27 10:14:10 +08:00
/**
* Given context and array of users , returns array of users whose enrolment status is suspended ,
* or enrolment has expired or has not started . Also removes those users from the given array
*
* @ param context $context context in which suspended users should be extracted .
* @ param array $users list of users .
* @ param array $ignoreusers array of user ids to ignore , e . g . guest
* @ return array list of suspended users .
*/
function extract_suspended_users ( $context , & $users , $ignoreusers = array ()) {
global $DB ;
// Get active enrolled users.
list ( $sql , $params ) = get_enrolled_sql ( $context , null , null , true );
$activeusers = $DB -> get_records_sql ( $sql , $params );
// Move suspended users to a separate array & remove from the initial one.
$susers = array ();
if ( sizeof ( $activeusers )) {
foreach ( $users as $userid => $user ) {
if ( ! array_key_exists ( $userid , $activeusers ) && ! in_array ( $userid , $ignoreusers )) {
$susers [ $userid ] = $user ;
unset ( $users [ $userid ]);
}
}
}
return $susers ;
}
/**
* Given context and array of users , returns array of user ids whose enrolment status is suspended ,
* or enrolment has expired or not started .
*
* @ param context $context context in which user enrolment is checked .
2014-07-08 09:52:41 +12:00
* @ param bool $usecache Enable or disable ( default ) the request cache
2013-03-27 10:14:10 +08:00
* @ return array list of suspended user id ' s .
*/
2014-06-25 17:33:10 +09:30
function get_suspended_userids ( context $context , $usecache = false ) {
2013-03-27 10:14:10 +08:00
global $DB ;
2014-06-25 17:33:10 +09:30
if ( $usecache ) {
2014-07-08 09:52:41 +12:00
$cache = cache :: make ( 'core' , 'suspended_userids' );
2014-06-25 17:33:10 +09:30
$susers = $cache -> get ( $context -> id );
if ( $susers !== false ) {
return $susers ;
}
}
2015-03-05 11:37:21 +10:30
$coursecontext = $context -> get_course_context ();
2013-03-27 10:14:10 +08:00
$susers = array ();
2015-03-05 11:37:21 +10:30
// Front page users are always enrolled, so suspended list is empty.
if ( $coursecontext -> instanceid != SITEID ) {
list ( $sql , $params ) = get_enrolled_sql ( $context , null , null , false , true );
$susers = $DB -> get_fieldset_sql ( $sql , $params );
$susers = array_combine ( $susers , $susers );
2013-03-27 10:14:10 +08:00
}
2014-06-25 17:33:10 +09:30
// Cache results for the remainder of this request.
if ( $usecache ) {
$cache -> set ( $context -> id , $susers );
}
2013-03-27 10:14:10 +08:00
return $susers ;
}
2016-08-12 15:13:09 +01:00
/**
2016-08-19 17:21:19 +01:00
* Gets sql for finding users with capability in the given context
2016-08-12 15:13:09 +01:00
*
* @ param context $context
2016-08-19 17:21:19 +01:00
* @ param string | array $capability Capability name or array of names .
* If an array is provided then this is the equivalent of a logical 'OR' ,
* i . e . the user needs to have one of these capabilities .
2016-08-12 15:13:09 +01:00
* @ return array ( $sql , $params )
*/
function get_with_capability_sql ( context $context , $capability ) {
static $i = 0 ;
$i ++ ;
$prefix = 'cu' . $i . '_' ;
$capjoin = get_with_capability_join ( $context , $capability , $prefix . 'u.id' );
$sql = " SELECT DISTINCT { $prefix } u.id
FROM { user } { $prefix } u
$capjoin -> joins
WHERE { $prefix } u . deleted = 0 AND $capjoin -> wheres " ;
return array ( $sql , $capjoin -> params );
}