Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/modinfolib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 // Maximum number of modinfo items to keep in memory cache. Do not increase this to a large
00028 // number because:
00029 // a) modinfo can be big (megabyte range) for some courses
00030 // b) performance of cache will deteriorate if there are very many items in it
00031 if (!defined('MAX_MODINFO_CACHE_SIZE')) {
00032     define('MAX_MODINFO_CACHE_SIZE', 10);
00033 }
00034 
00035 
00043 class course_modinfo extends stdClass {
00044     // For convenience we store the course object here as it is needed in other parts of code
00045     private $course;
00046 
00047     // Existing data fields
00049 
00050     // These are public for backward compatibility. Note: it is not possible to retain BC
00051     // using PHP magic get methods because behaviour is different with regard to empty().
00052 
00058     public $courseid;
00059 
00065     public $userid;
00066 
00073     public $sections;
00074 
00080     public $cms;
00081 
00087     public $instances;
00088 
00096     public $groups;
00097 
00098     // Get methods for data
00100 
00104     public function get_course() {
00105         return $this->course;
00106     }
00107 
00111     public function get_course_id() {
00112         return $this->courseid;
00113     }
00114 
00118     public function get_user_id() {
00119         return $this->userid;
00120     }
00121 
00126     public function get_sections() {
00127         return $this->sections;
00128     }
00129 
00134     public function get_cms() {
00135         return $this->cms;
00136     }
00137 
00144     public function get_cm($cmid) {
00145         if (empty($this->cms[$cmid])) {
00146             throw new moodle_exception('invalidcoursemodule', 'error');
00147         }
00148         return $this->cms[$cmid];
00149     }
00150 
00155     public function get_instances() {
00156         return $this->instances;
00157     }
00158 
00164     public function get_instances_of($modname) {
00165         if (empty($this->instances[$modname])) {
00166             return array();
00167         }
00168         return $this->instances[$modname];
00169     }
00170 
00177     public function get_groups($groupingid=0) {
00178         if (is_null($this->groups)) {
00179             // NOTE: Performance could be improved here. The system caches user groups
00180             // in $USER->groupmember[$courseid] => array of groupid=>groupid. Unfortunately this
00181             // structure does not include grouping information. It probably could be changed to
00182             // do so, without a significant performance hit on login, thus saving this one query
00183             // each request.
00184             $this->groups = groups_get_user_groups($this->courseid, $this->userid);
00185         }
00186         if (!isset($this->groups[$groupingid])) {
00187             return array();
00188         }
00189         return $this->groups[$groupingid];
00190     }
00191 
00199     public function __construct($course, $userid) {
00200         global $CFG, $DB;
00201 
00202         // Set initial values
00203         $this->courseid = $course->id;
00204         $this->userid = $userid;
00205         $this->sections = array();
00206         $this->cms = array();
00207         $this->instances = array();
00208         $this->groups = null;
00209         $this->course = $course;
00210 
00211         // Check modinfo field is set. If not, build and load it.
00212         if (empty($course->modinfo)) {
00213             rebuild_course_cache($course->id);
00214             $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
00215         }
00216 
00217         // Load modinfo field into memory as PHP object and check it's valid
00218         $info = unserialize($course->modinfo);
00219         if (!is_array($info)) {
00220             // hmm, something is wrong - lets try to fix it
00221             rebuild_course_cache($course->id);
00222             $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
00223             $info = unserialize($course->modinfo);
00224             if (!is_array($info)) {
00225                 // If it still fails, abort
00226                 debugging('Problem with "modinfo" data for this course');
00227                 return;
00228             }
00229         }
00230 
00231         // If we haven't already preloaded contexts for the course, do it now
00232         preload_course_contexts($course->id);
00233 
00234         // Loop through each piece of module data, constructing it
00235         $modexists = array();
00236         foreach ($info as $mod) {
00237             if (empty($mod->name)) {
00238                 // something is wrong here
00239                 continue;
00240             }
00241 
00242             // Skip modules which don't exist
00243             if (empty($modexists[$mod->mod])) {
00244                 if (!file_exists("$CFG->dirroot/mod/$mod->mod/lib.php")) {
00245                     continue;
00246                 }
00247                 $modexists[$mod->mod] = true;
00248             }
00249 
00250             // Construct info for this module
00251             $cm = new cm_info($this, $course, $mod, $info);
00252 
00253             // Store module in instances and cms array
00254             if (!isset($this->instances[$cm->modname])) {
00255                 $this->instances[$cm->modname] = array();
00256             }
00257             $this->instances[$cm->modname][$cm->instance] = $cm;
00258             $this->cms[$cm->id] = $cm;
00259 
00260             // Reconstruct sections. This works because modules are stored in order
00261             if (!isset($this->sections[$cm->sectionnum])) {
00262                 $this->sections[$cm->sectionnum] = array();
00263             }
00264             $this->sections[$cm->sectionnum][] = $cm->id;
00265         }
00266 
00267         // We need at least 'dynamic' data from each course-module (this is basically the remaining
00268         // data which was always present in previous version of get_fast_modinfo, so it's required
00269         // for BC). Creating it in a second pass is necessary because obtain_dynamic_data sometimes
00270         // needs to be able to refer to a 'complete' (with basic data) modinfo.
00271         foreach ($this->cms as $cm) {
00272             $cm->obtain_dynamic_data();
00273         }
00274     }
00275 }
00276 
00277 
00286 class cm_info extends stdClass  {
00290     const STATE_BASIC = 0;
00291 
00295     const STATE_DYNAMIC = 1;
00296 
00300     const STATE_VIEW = 2;
00301 
00306     private $modinfo;
00307 
00312     private $state;
00313 
00314     // Existing data fields
00316 
00321     public $id;
00322 
00327     public $instance;
00328 
00333     public $course;
00334 
00340     public $idnumber;
00341 
00346     public $added;
00347 
00355     public $score;
00356 
00362     public $visible;
00363 
00369     public $visibleold;
00370 
00376     public $groupmode;
00377 
00382     public $groupingid;
00383 
00390     public $groupmembersonly;
00391 
00396     public $indent;
00397 
00403     public $completion;
00404 
00411     public $completiongradeitemnumber;
00412 
00417     public $completionview;
00418 
00424     public $completionexpected;
00425 
00431     public $availablefrom;
00432 
00438     public $availableuntil;
00439 
00446     public $showavailability;
00447 
00454     public $showdescription;
00455 
00462     public $extra;
00463 
00468     public $icon;
00469 
00474     public $iconcomponent;
00475 
00481     public $modname;
00482 
00487     public $module;
00488 
00494     public $name;
00495 
00501     public $sectionnum;
00502 
00507     public $section;
00508 
00515     public $conditionscompletion;
00516 
00522     public $conditionsgrade;
00523 
00530     public $modplural;
00531 
00537     public $available;
00538 
00545     public $availableinfo;
00546 
00553     public $uservisible;
00554 
00560     public $context;
00561 
00562 
00563     // New data available only via functions
00565 
00569     private $url;
00570 
00574     private $content;
00575 
00579     private $extraclasses;
00580 
00584     private $iconurl;
00585 
00589     private $onclick;
00590 
00594     private $customdata;
00595 
00599     private $afterlink;
00600 
00604     private $afterediticons;
00605 
00611     public function has_view() {
00612         return !is_null($this->url);
00613     }
00614 
00618     public function get_url() {
00619         return $this->url;
00620     }
00621 
00627     public function get_content() {
00628         $this->obtain_view_data();
00629         return $this->content;
00630     }
00631 
00636     public function get_extra_classes() {
00637         $this->obtain_view_data();
00638         return $this->extraclasses;
00639     }
00640 
00645     public function get_on_click() {
00646         // Does not need view data; may be used by navigation
00647         return $this->onclick;
00648     }
00652     public function get_custom_data() {
00653         return $this->customdata;
00654     }
00655 
00660     public function get_after_link() {
00661         $this->obtain_view_data();
00662         return $this->afterlink;
00663     }
00664 
00669     public function get_after_edit_icons() {
00670         $this->obtain_view_data();
00671         return $this->afterediticons;
00672     }
00673 
00678     public function get_icon_url($output = null) {
00679         global $OUTPUT;
00680         if (!$output) {
00681             $output = $OUTPUT;
00682         }
00683         // Support modules setting their own, external, icon image
00684         if (!empty($this->iconurl)) {
00685             $icon = $this->iconurl;
00686 
00687         // Fallback to normal local icon + component procesing
00688         } else if (!empty($this->icon)) {
00689             if (substr($this->icon, 0, 4) === 'mod/') {
00690                 list($modname, $iconname) = explode('/', substr($this->icon, 4), 2);
00691                 $icon = $output->pix_url($iconname, $modname);
00692             } else {
00693                 if (!empty($this->iconcomponent)) {
00694                     // Icon  has specified component
00695                     $icon = $output->pix_url($this->icon, $this->iconcomponent);
00696                 } else {
00697                     // Icon does not have specified component, use default
00698                     $icon = $output->pix_url($this->icon);
00699                 }
00700             }
00701         } else {
00702             $icon = $output->pix_url('icon', $this->modname);
00703         }
00704         return $icon;
00705     }
00706 
00710     public function get_modinfo() {
00711         return $this->modinfo;
00712     }
00713 
00717     public function get_course() {
00718         return $this->modinfo->get_course();
00719     }
00720 
00721     // Set functions
00723 
00729     public function set_content($content) {
00730         $this->content = $content;
00731     }
00732 
00738     public function set_extra_classes($extraclasses) {
00739         $this->extraclasses = $extraclasses;
00740     }
00741 
00750     public function set_icon_url(moodle_url $iconurl) {
00751         $this->iconurl = $iconurl;
00752     }
00753 
00761     public function set_on_click($onclick) {
00762         $this->check_not_view_only();
00763         $this->onclick = $onclick;
00764     }
00765 
00771     public function set_after_link($afterlink) {
00772         $this->afterlink = $afterlink;
00773     }
00774 
00780     public function set_after_edit_icons($afterediticons) {
00781         $this->afterediticons = $afterediticons;
00782     }
00783 
00790     public function set_name($name) {
00791         $this->update_user_visible();
00792         $this->name = $name;
00793     }
00794 
00800     public function set_no_view_link() {
00801         $this->check_not_view_only();
00802         $this->url = null;
00803     }
00804 
00812     public function set_user_visible($uservisible) {
00813         $this->check_not_view_only();
00814         $this->uservisible = $uservisible;
00815     }
00816 
00834     public function set_available($available, $showavailability=0, $availableinfo='') {
00835         $this->check_not_view_only();
00836         $this->available = $available;
00837         $this->showavailability = $showavailability;
00838         $this->availableinfo = $availableinfo;
00839         $this->update_user_visible();
00840     }
00841 
00849     private function check_not_view_only() {
00850         if ($this->state >= self::STATE_DYNAMIC) {
00851             throw new coding_exception('Cannot set this data from _cm_info_view because it may ' .
00852                     'affect other pages as well as view');
00853         }
00854     }
00855 
00863     public function __construct(course_modinfo $modinfo, $course, $mod, $info) {
00864         global $CFG;
00865         $this->modinfo = $modinfo;
00866 
00867         $this->id               = $mod->cm;
00868         $this->instance         = $mod->id;
00869         $this->course           = $course->id;
00870         $this->modname          = $mod->mod;
00871         $this->idnumber         = isset($mod->idnumber) ? $mod->idnumber : '';
00872         $this->name             = $mod->name;
00873         $this->visible          = $mod->visible;
00874         $this->sectionnum       = $mod->section; // Note weirdness with name here
00875         $this->groupmode        = isset($mod->groupmode) ? $mod->groupmode : 0;
00876         $this->groupingid       = isset($mod->groupingid) ? $mod->groupingid : 0;
00877         $this->groupmembersonly = isset($mod->groupmembersonly) ? $mod->groupmembersonly : 0;
00878         $this->indent           = isset($mod->indent) ? $mod->indent : 0;
00879         $this->extra            = isset($mod->extra) ? $mod->extra : '';
00880         $this->extraclasses     = isset($mod->extraclasses) ? $mod->extraclasses : '';
00881         $this->iconurl          = isset($mod->iconurl) ? $mod->iconurl : '';
00882         $this->onclick          = isset($mod->onclick) ? $mod->onclick : '';
00883         $this->content          = isset($mod->content) ? $mod->content : '';
00884         $this->icon             = isset($mod->icon) ? $mod->icon : '';
00885         $this->iconcomponent    = isset($mod->iconcomponent) ? $mod->iconcomponent : '';
00886         $this->customdata       = isset($mod->customdata) ? $mod->customdata : '';
00887         $this->context          = get_context_instance(CONTEXT_MODULE, $mod->cm);
00888         $this->showdescription  = isset($mod->showdescription) ? $mod->showdescription : 0;
00889         $this->state = self::STATE_BASIC;
00890 
00891         // This special case handles old label data. Labels used to use the 'name' field for
00892         // content
00893         if ($this->modname === 'label' && $this->content === '') {
00894             $this->content = $this->extra;
00895             $this->extra = '';
00896         }
00897 
00898         // Note: These fields from $cm were not present in cm_info in Moodle
00899         // 2.0.2 and prior. They may not be available if course cache hasn't
00900         // been rebuilt since then.
00901         $this->section = isset($mod->sectionid) ? $mod->sectionid : 0;
00902         $this->module = isset($mod->module) ? $mod->module : 0;
00903         $this->added = isset($mod->added) ? $mod->added : 0;
00904         $this->score = isset($mod->score) ? $mod->score : 0;
00905         $this->visibleold = isset($mod->visibleold) ? $mod->visibleold : 0;
00906 
00907         // Note: it saves effort and database space to always include the
00908         // availability and completion fields, even if availability or completion
00909         // are actually disabled
00910         $this->completion = isset($mod->completion) ? $mod->completion : 0;
00911         $this->completiongradeitemnumber = isset($mod->completiongradeitemnumber)
00912                 ? $mod->completiongradeitemnumber : null;
00913         $this->completionview = isset($mod->completionview)
00914                 ? $mod->completionview : 0;
00915         $this->completionexpected = isset($mod->completionexpected)
00916                 ? $mod->completionexpected : 0;
00917         $this->showavailability = isset($mod->showavailability) ? $mod->showavailability : 0;
00918         $this->availablefrom = isset($mod->availablefrom) ? $mod->availablefrom : 0;
00919         $this->availableuntil = isset($mod->availableuntil) ? $mod->availableuntil : 0;
00920         $this->conditionscompletion = isset($mod->conditionscompletion)
00921                 ? $mod->conditionscompletion : array();
00922         $this->conditionsgrade = isset($mod->conditionsgrade)
00923                 ? $mod->conditionsgrade : array();
00924 
00925         // Get module plural name.
00926         // TODO This was a very old performance hack and should now be removed as the information
00927         // certainly doesn't belong in modinfo. On a 'normal' page this is only used in the
00928         // activity_modules block, so if it needs caching, it should be cached there.
00929         static $modplurals;
00930         if (!isset($modplurals[$this->modname])) {
00931             $modplurals[$this->modname] = get_string('modulenameplural', $this->modname);
00932         }
00933         $this->modplural = $modplurals[$this->modname];
00934 
00935         static $modviews;
00936         if (!isset($modviews[$this->modname])) {
00937             $modviews[$this->modname] = !plugin_supports('mod', $this->modname,
00938                     FEATURE_NO_VIEW_LINK);
00939         }
00940         $this->url = $modviews[$this->modname]
00941                 ? new moodle_url('/mod/' . $this->modname . '/view.php', array('id'=>$this->id))
00942                 : null;
00943     }
00944 
00959     public function obtain_dynamic_data() {
00960         global $CFG;
00961         if ($this->state >= self::STATE_DYNAMIC) {
00962             return;
00963         }
00964         $userid = $this->modinfo->get_user_id();
00965 
00966         if (!empty($CFG->enableavailability)) {
00967             // Get availability information
00968             $ci = new condition_info($this);
00969             // Note that the modinfo currently available only includes minimal details (basic data)
00970             // so passing it to this function is a bit dangerous as it would cause infinite
00971             // recursion if it tried to get dynamic data, however we know that this function only
00972             // uses basic data.
00973             $this->available = $ci->is_available($this->availableinfo, true,
00974                     $userid, $this->modinfo);
00975         } else {
00976             $this->available = true;
00977         }
00978 
00979         // Update visible state for current user
00980         $this->update_user_visible();
00981 
00982         // Let module make dynamic changes at this point
00983         $this->call_mod_function('cm_info_dynamic');
00984         $this->state = self::STATE_DYNAMIC;
00985     }
00986 
00992     private function update_user_visible() {
00993         global $CFG;
00994         $modcontext = get_context_instance(CONTEXT_MODULE, $this->id);
00995         $userid = $this->modinfo->get_user_id();
00996         $this->uservisible = true;
00997         if ((!$this->visible or !$this->available) and
00998                 !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
00999             // If the activity is hidden or unavailable, and you don't have viewhiddenactivities,
01000             // set it so that user can't see or access it
01001             $this->uservisible = false;
01002         } else if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
01003                 and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
01004             // If the activity has 'group members only' and you don't have accessallgroups...
01005             $groups = $this->modinfo->get_groups($this->groupingid);
01006             if (empty($groups)) {
01007                 // ...and you don't belong to a group, then set it so you can't see/access it
01008                 $this->uservisible = false;
01009             }
01010         }
01011     }
01012 
01019     private function call_mod_function($type) {
01020         global $CFG;
01021         $libfile = $CFG->dirroot . '/mod/' . $this->modname . '/lib.php';
01022         if (file_exists($libfile)) {
01023             include_once($libfile);
01024             $function = 'mod_' . $this->modname . '_' . $type;
01025             if (function_exists($function)) {
01026                 $function($this);
01027             } else {
01028                 $function = $this->modname . '_' . $type;
01029                 if (function_exists($function)) {
01030                     $function($this);
01031                 }
01032             }
01033         }
01034     }
01035 
01050     private function obtain_view_data() {
01051         if ($this->state >= self::STATE_VIEW) {
01052             return;
01053         }
01054 
01055         // Let module make changes at this point
01056         $this->call_mod_function('cm_info_view');
01057         $this->state = self::STATE_VIEW;
01058     }
01059 }
01060 
01061 
01074 function get_fast_modinfo(&$course, $userid=0) {
01075     global $CFG, $USER, $DB;
01076     require_once($CFG->dirroot.'/course/lib.php');
01077 
01078     if (!empty($CFG->enableavailability)) {
01079         require_once($CFG->libdir.'/conditionlib.php');
01080     }
01081 
01082     static $cache = array();
01083 
01084     if ($course === 'reset') {
01085         $cache = array();
01086         return null;
01087     }
01088 
01089     if (empty($userid)) {
01090         $userid = $USER->id;
01091     }
01092 
01093     if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
01094         return $cache[$course->id];
01095     }
01096 
01097     if (!property_exists($course, 'modinfo')) {
01098         debugging('Coding problem - missing course modinfo property in get_fast_modinfo() call');
01099     }
01100 
01101     unset($cache[$course->id]); // prevent potential reference problems when switching users
01102 
01103     $cache[$course->id] = new course_modinfo($course, $userid);
01104 
01105     // Ensure cache does not use too much RAM
01106     if (count($cache) > MAX_MODINFO_CACHE_SIZE) {
01107         reset($cache);
01108         $key = key($cache);
01109         unset($cache[$key]->instances);
01110         unset($cache[$key]->cms);
01111         unset($cache[$key]);
01112     }
01113 
01114     return $cache[$course->id];
01115 }
01116 
01122 function rebuild_course_cache($courseid=0, $clearonly=false) {
01123     global $COURSE, $DB, $CFG;
01124 
01125     // Destroy navigation caches
01126     navigation_cache::destroy_volatile_caches();
01127 
01128     if ($clearonly) {
01129         if (empty($courseid)) {
01130             $courseselect = array();
01131         } else {
01132             $courseselect = array('id'=>$courseid);
01133         }
01134         $DB->set_field('course', 'modinfo', null, $courseselect);
01135         // update cached global COURSE too ;-)
01136         if ($courseid == $COURSE->id or empty($courseid)) {
01137             $COURSE->modinfo = null;
01138         }
01139         // reset the fast modinfo cache
01140         $reset = 'reset';
01141         get_fast_modinfo($reset);
01142         return;
01143     }
01144 
01145     require_once("$CFG->dirroot/course/lib.php");
01146 
01147     if ($courseid) {
01148         $select = array('id'=>$courseid);
01149     } else {
01150         $select = array();
01151         @set_time_limit(0);  // this could take a while!   MDL-10954
01152     }
01153 
01154     $rs = $DB->get_recordset("course", $select,'','id,fullname');
01155     foreach ($rs as $course) {
01156         $modinfo = serialize(get_array_of_activities($course->id));
01157         $DB->set_field("course", "modinfo", $modinfo, array("id"=>$course->id));
01158         // update cached global COURSE too ;-)
01159         if ($course->id == $COURSE->id) {
01160             $COURSE->modinfo = $modinfo;
01161         }
01162     }
01163     $rs->close();
01164     // reset the fast modinfo cache
01165     $reset = 'reset';
01166     get_fast_modinfo($reset);
01167 }
01168 
01169 
01178 class cached_cm_info {
01183     public $name;
01184 
01194     public $icon;
01195 
01202     public $iconcomponent;
01203 
01208     public $content;
01209 
01216     public $customdata;
01217 
01223     public $extraclasses;
01224 
01230     public $iconurl;
01231 
01236     public $onclick;
01237 }
 All Data Structures Namespaces Files Functions Variables Enumerations