Merge branch 'MDL-29569' of git://github.com/rwijaya/moodle
[moodle.git] / lib / conditionlib.php
blobf3279a19dbc2fe7de50a19643ded29989b00b794
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Used for tracking conditions that apply before activities are displayed
19 * to students ('conditional availability').
21 * @package core
22 * @subpackage condition
23 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
29 /** The activity is not displayed to students at all when conditions aren't met. */
30 define('CONDITION_STUDENTVIEW_HIDE',0);
31 /** The activity is displayed to students as a greyed-out name, with informational
32 text that explains the conditions under which it will be available. */
33 define('CONDITION_STUDENTVIEW_SHOW',1);
35 /** The $cm variable is expected to contain all completion-related data */
36 define('CONDITION_MISSING_NOTHING',0);
37 /** The $cm variable is expected to contain the fields from course_modules but
38 not the course_modules_availability data */
39 define('CONDITION_MISSING_EXTRATABLE',1);
40 /** The $cm variable is expected to contain nothing except the ID */
41 define('CONDITION_MISSING_EVERYTHING',2);
43 require_once($CFG->libdir.'/completionlib.php');
45 /**
46 * @global stdClass $CONDITIONLIB_PRIVATE
47 * @name $CONDITIONLIB_PRIVATE
49 global $CONDITIONLIB_PRIVATE;
50 $CONDITIONLIB_PRIVATE = new stdClass;
51 // Caches whether completion values are used in availability conditions.
52 // Array of course => array of cmid => true.
53 $CONDITIONLIB_PRIVATE->usedincondition = array();
55 /**
56 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
57 * @package moodlecore
59 class condition_info {
60 /**
61 * @var object, bool
63 private $cm, $gotdata;
65 /**
66 * Constructs with course-module details.
68 * @global object
69 * @uses CONDITION_MISSING_NOTHING
70 * @uses CONDITION_MISSING_EVERYTHING
71 * @uses DEBUG_DEVELOPER
72 * @uses CONDITION_MISSING_EXTRATABLE
73 * @param object $cm Moodle course-module object. May have extra fields
74 * ->conditionsgrade, ->conditionscompletion which should come from
75 * get_fast_modinfo. Should have ->availablefrom, ->availableuntil,
76 * and ->showavailability, ->course; but the only required thing is ->id.
77 * @param int $expectingmissing Used to control whether or not a developer
78 * debugging message (performance warning) will be displayed if some of
79 * the above data is missing and needs to be retrieved; a
80 * CONDITION_MISSING_xx constant
81 * @param bool $loaddata If you need a 'write-only' object, set this value
82 * to false to prevent database access from constructor
83 * @return condition_info Object which can retrieve information about the
84 * activity
86 public function __construct($cm, $expectingmissing=CONDITION_MISSING_NOTHING,
87 $loaddata=true) {
88 global $DB;
90 // Check ID as otherwise we can't do the other queries
91 if (empty($cm->id)) {
92 throw new coding_exception("Invalid parameters; course-module ID not included");
95 // If not loading data, don't do anything else
96 if (!$loaddata) {
97 $this->cm = (object)array('id'=>$cm->id);
98 $this->gotdata = false;
99 return;
102 // Missing basic data from course_modules
103 if (!isset($cm->availablefrom) || !isset($cm->availableuntil) ||
104 !isset($cm->showavailability) || !isset($cm->course)) {
105 if ($expectingmissing<CONDITION_MISSING_EVERYTHING) {
106 debugging('Performance warning: condition_info constructor is
107 faster if you pass in $cm with at least basic fields
108 (availablefrom,availableuntil,showavailability,course).
109 [This warning can be disabled, see phpdoc.]',
110 DEBUG_DEVELOPER);
112 $cm = $DB->get_record('course_modules',array('id'=>$cm->id),
113 'id,course,availablefrom,availableuntil,showavailability');
116 $this->cm = clone($cm);
117 $this->gotdata = true;
119 // Missing extra data
120 if (!isset($cm->conditionsgrade) || !isset($cm->conditionscompletion)) {
121 if ($expectingmissing<CONDITION_MISSING_EXTRATABLE) {
122 debugging('Performance warning: condition_info constructor is
123 faster if you pass in a $cm from get_fast_modinfo.
124 [This warning can be disabled, see phpdoc.]',
125 DEBUG_DEVELOPER);
128 self::fill_availability_conditions($this->cm);
133 * Adds the extra availability conditions (if any) into the given
134 * course-module object.
136 * @global object
137 * @global object
138 * @param object $cm Moodle course-module data object
140 public static function fill_availability_conditions(&$cm) {
141 if (empty($cm->id)) {
142 throw new coding_exception("Invalid parameters; course-module ID not included");
145 // Does nothing if the variables are already present
146 if (!isset($cm->conditionsgrade) ||
147 !isset($cm->conditionscompletion)) {
148 $cm->conditionsgrade=array();
149 $cm->conditionscompletion=array();
151 global $DB, $CFG;
152 $conditions = $DB->get_records_sql($sql="
153 SELECT
154 cma.id as cmaid, gi.*,cma.sourcecmid,cma.requiredcompletion,cma.gradeitemid,
155 cma.grademin as conditiongrademin, cma.grademax as conditiongrademax
156 FROM
157 {course_modules_availability} cma
158 LEFT JOIN {grade_items} gi ON gi.id=cma.gradeitemid
159 WHERE
160 coursemoduleid=?",array($cm->id));
161 foreach ($conditions as $condition) {
162 if (!is_null($condition->sourcecmid)) {
163 $cm->conditionscompletion[$condition->sourcecmid] =
164 $condition->requiredcompletion;
165 } else {
166 $minmax = new stdClass;
167 $minmax->min = $condition->conditiongrademin;
168 $minmax->max = $condition->conditiongrademax;
169 $minmax->name = self::get_grade_name($condition);
170 $cm->conditionsgrade[$condition->gradeitemid] = $minmax;
177 * Obtains the name of a grade item.
179 * @global object
180 * @param object $gradeitemobj Object from get_record on grade_items table,
181 * (can be empty if you want to just get !missing)
182 * @return string Name of item of !missing if it didn't exist
184 private static function get_grade_name($gradeitemobj) {
185 global $CFG;
186 if (isset($gradeitemobj->id)) {
187 require_once($CFG->libdir.'/gradelib.php');
188 $item = new grade_item;
189 grade_object::set_properties($item, $gradeitemobj);
190 return $item->get_name();
191 } else {
192 return '!missing'; // Ooops, missing grade
197 * @see require_data()
198 * @return object A course-module object with all the information required to
199 * determine availability.
201 public function get_full_course_module() {
202 $this->require_data();
203 return $this->cm;
207 * Adds to the database a condition based on completion of another module.
209 * @global object
210 * @param int $cmid ID of other module
211 * @param int $requiredcompletion COMPLETION_xx constant
213 public function add_completion_condition($cmid, $requiredcompletion) {
214 // Add to DB
215 global $DB;
216 $DB->insert_record('course_modules_availability',
217 (object)array('coursemoduleid'=>$this->cm->id,
218 'sourcecmid'=>$cmid, 'requiredcompletion'=>$requiredcompletion),
219 false);
221 // Store in memory too
222 $this->cm->conditionscompletion[$cmid] = $requiredcompletion;
226 * Adds to the database a condition based on the value of a grade item.
228 * @global object
229 * @param int $gradeitemid ID of grade item
230 * @param float $min Minimum grade (>=), up to 5 decimal points, or null if none
231 * @param float $max Maximum grade (<), up to 5 decimal points, or null if none
232 * @param bool $updateinmemory If true, updates data in memory; otherwise,
233 * memory version may be out of date (this has performance consequences,
234 * so don't do it unless it really needs updating)
236 public function add_grade_condition($gradeitemid, $min, $max, $updateinmemory=false) {
237 // Normalise nulls
238 if ($min==='') {
239 $min = null;
241 if ($max==='') {
242 $max = null;
244 // Add to DB
245 global $DB;
246 $DB->insert_record('course_modules_availability',
247 (object)array('coursemoduleid'=>$this->cm->id,
248 'gradeitemid'=>$gradeitemid, 'grademin'=>$min, 'grademax'=>$max),
249 false);
251 // Store in memory too
252 if ($updateinmemory) {
253 $this->cm->conditionsgrade[$gradeitemid]=(object)array(
254 'min'=>$min, 'max'=>$max);
255 $this->cm->conditionsgrade[$gradeitemid]->name =
256 self::get_grade_name($DB->get_record('grade_items',
257 array('id'=>$gradeitemid)));
262 * Erases from the database all conditions for this activity.
264 * @global object
266 public function wipe_conditions() {
267 // Wipe from DB
268 global $DB;
269 $DB->delete_records('course_modules_availability',
270 array('coursemoduleid'=>$this->cm->id));
272 // And from memory
273 $this->cm->conditionsgrade = array();
274 $this->cm->conditionscompletion = array();
278 * Obtains a string describing all availability restrictions (even if
279 * they do not apply any more).
281 * @global object
282 * @global object
283 * @param object $modinfo Usually leave as null for default. Specify when
284 * calling recursively from inside get_fast_modinfo. The value supplied
285 * here must include list of all CMs with 'id' and 'name'
286 * @return string Information string (for admin) about all restrictions on
287 * this item
289 public function get_full_information($modinfo=null) {
290 $this->require_data();
291 global $COURSE, $DB;
293 $information = '';
295 // Completion conditions
296 if(count($this->cm->conditionscompletion)>0) {
297 if ($this->cm->course==$COURSE->id) {
298 $course = $COURSE;
299 } else {
300 $course = $DB->get_record('course',array('id'=>$this->cm->course),'id,enablecompletion,modinfo');
302 foreach ($this->cm->conditionscompletion as $cmid=>$expectedcompletion) {
303 if (!$modinfo) {
304 $modinfo = get_fast_modinfo($course);
306 if (empty($modinfo->cms[$cmid])) {
307 continue;
309 $information .= get_string(
310 'requires_completion_'.$expectedcompletion,
311 'condition', $modinfo->cms[$cmid]->name).' ';
315 // Grade conditions
316 if (count($this->cm->conditionsgrade)>0) {
317 foreach ($this->cm->conditionsgrade as $gradeitemid=>$minmax) {
318 // String depends on type of requirement. We are coy about
319 // the actual numbers, in case grades aren't released to
320 // students.
321 if (is_null($minmax->min) && is_null($minmax->max)) {
322 $string = 'any';
323 } else if (is_null($minmax->max)) {
324 $string = 'min';
325 } else if (is_null($minmax->min)) {
326 $string = 'max';
327 } else {
328 $string = 'range';
330 $information .= get_string('requires_grade_'.$string, 'condition', $minmax->name).' ';
334 // The date logic is complicated. The intention of this logic is:
335 // 1) display date without time where possible (whenever the date is
336 // midnight)
337 // 2) when the 'until' date is e.g. 00:00 on the 14th, we display it as
338 // 'until the 13th' (experience at the OU showed that students are
339 // likely to interpret 'until <date>' as 'until the end of <date>').
340 // 3) This behaviour becomes confusing for 'same-day' dates where there
341 // are some exceptions.
342 // Users in different time zones will typically not get the 'abbreviated'
343 // behaviour but it should work OK for them aside from that.
345 // The following cases are possible:
346 // a) From 13:05 on 14 Oct until 12:10 on 17 Oct (exact, exact)
347 // b) From 14 Oct until 12:11 on 17 Oct (midnight, exact)
348 // c) From 13:05 on 14 Oct until 17 Oct (exact, midnight 18 Oct)
349 // d) From 14 Oct until 17 Oct (midnight 14 Oct, midnight 18 Oct)
350 // e) On 14 Oct (midnight 14 Oct, midnight 15 Oct)
351 // f) From 13:05 on 14 Oct until 0:00 on 15 Oct (exact, midnight, same day)
352 // g) From 0:00 on 14 Oct until 12:05 on 14 Oct (midnight, exact, same day)
353 // h) From 13:05 on 14 Oct (exact)
354 // i) From 14 Oct (midnight)
355 // j) Until 13:05 on 14 Oct (exact)
356 // k) Until 14 Oct (midnight 15 Oct)
358 // Check if start and end dates are 'midnights', if so we show in short form
359 $shortfrom = self::is_midnight($this->cm->availablefrom);
360 $shortuntil = self::is_midnight($this->cm->availableuntil);
362 // For some checks and for display, we need the previous day for the 'until'
363 // value, if we are going to display it in short form
364 if ($this->cm->availableuntil) {
365 $daybeforeuntil = strtotime("-1 day", usergetmidnight($this->cm->availableuntil));
368 // Special case for if one but not both are exact and they are within a day
369 if ($this->cm->availablefrom && $this->cm->availableuntil &&
370 $shortfrom != $shortuntil && $daybeforeuntil < $this->cm->availablefrom) {
371 // Don't use abbreviated version (see examples f, g above)
372 $shortfrom = false;
373 $shortuntil = false;
376 // When showing short end date, the display time is the 'day before' one
377 $displayuntil = $shortuntil ? $daybeforeuntil : $this->cm->availableuntil;
379 if ($this->cm->availablefrom && $this->cm->availableuntil) {
380 if ($shortfrom && $shortuntil && $daybeforeuntil == $this->cm->availablefrom) {
381 $information .= get_string('requires_date_both_single_day', 'condition',
382 self::show_time($this->cm->availablefrom, true));
383 } else {
384 $information .= get_string('requires_date_both', 'condition', (object)array(
385 'from' => self::show_time($this->cm->availablefrom, $shortfrom),
386 'until' => self::show_time($displayuntil, $shortuntil)));
388 } else if ($this->cm->availablefrom) {
389 $information .= get_string('requires_date', 'condition',
390 self::show_time($this->cm->availablefrom, $shortfrom));
391 } else if ($this->cm->availableuntil) {
392 $information .= get_string('requires_date_before', 'condition',
393 self::show_time($displayuntil, $shortuntil));
396 $information = trim($information);
397 return $information;
401 * Checks whether a given time refers exactly to midnight (in current user
402 * timezone).
403 * @param int $time Time
404 * @return bool True if time refers to midnight, false if it's some other
405 * time or if it is set to zero
407 private static function is_midnight($time) {
408 return $time && usergetmidnight($time) == $time;
412 * Determines whether this particular course-module is currently available
413 * according to these criteria.
415 * - This does not include the 'visible' setting (i.e. this might return
416 * true even if visible is false); visible is handled independently.
417 * - This does not take account of the viewhiddenactivities capability.
418 * That should apply later.
420 * @global object
421 * @global object
422 * @uses COMPLETION_COMPLETE
423 * @uses COMPLETION_COMPLETE_FAIL
424 * @uses COMPLETION_COMPLETE_PASS
425 * @param string $information If the item has availability restrictions,
426 * a string that describes the conditions will be stored in this variable;
427 * if this variable is set blank, that means don't display anything
428 * @param bool $grabthelot Performance hint: if true, caches information
429 * required for all course-modules, to make the front page and similar
430 * pages work more quickly (works only for current user)
431 * @param int $userid If set, specifies a different user ID to check availability for
432 * @param object $modinfo Usually leave as null for default. Specify when
433 * calling recursively from inside get_fast_modinfo. The value supplied
434 * here must include list of all CMs with 'id' and 'name'
435 * @return bool True if this item is available to the user, false otherwise
437 public function is_available(&$information, $grabthelot=false, $userid=0, $modinfo=null) {
438 $this->require_data();
439 global $COURSE,$DB;
441 $available = true;
442 $information = '';
444 // Check each completion condition
445 if(count($this->cm->conditionscompletion)>0) {
446 if ($this->cm->course==$COURSE->id) {
447 $course = $COURSE;
448 } else {
449 $course = $DB->get_record('course',array('id'=>$this->cm->course),'id,enablecompletion,modinfo');
452 $completion = new completion_info($course);
453 foreach ($this->cm->conditionscompletion as $cmid=>$expectedcompletion) {
454 // If this depends on a deleted module, handle that situation
455 // gracefully.
456 if (!$modinfo) {
457 $modinfo = get_fast_modinfo($course);
459 if (empty($modinfo->cms[$cmid])) {
460 global $PAGE, $UNITTEST;
461 if (!empty($UNITTEST) || (isset($PAGE) && strpos($PAGE->pagetype, 'course-view-')===0)) {
462 debugging("Warning: activity {$this->cm->id} '{$this->cm->name}' has condition on deleted activity $cmid (to get rid of this message, edit the named activity)");
464 continue;
467 // The completion system caches its own data
468 $completiondata = $completion->get_data((object)array('id'=>$cmid),
469 $grabthelot, $userid, $modinfo);
471 $thisisok = true;
472 if ($expectedcompletion==COMPLETION_COMPLETE) {
473 // 'Complete' also allows the pass, fail states
474 switch ($completiondata->completionstate) {
475 case COMPLETION_COMPLETE:
476 case COMPLETION_COMPLETE_FAIL:
477 case COMPLETION_COMPLETE_PASS:
478 break;
479 default:
480 $thisisok = false;
482 } else {
483 // Other values require exact match
484 if ($completiondata->completionstate!=$expectedcompletion) {
485 $thisisok = false;
488 if (!$thisisok) {
489 $available = false;
490 $information .= get_string(
491 'requires_completion_'.$expectedcompletion,
492 'condition',$modinfo->cms[$cmid]->name).' ';
497 // Check each grade condition
498 if (count($this->cm->conditionsgrade)>0) {
499 foreach ($this->cm->conditionsgrade as $gradeitemid=>$minmax) {
500 $score = $this->get_cached_grade_score($gradeitemid, $grabthelot, $userid);
501 if ($score===false ||
502 (!is_null($minmax->min) && $score<$minmax->min) ||
503 (!is_null($minmax->max) && $score>=$minmax->max)) {
504 // Grade fail
505 $available = false;
506 // String depends on type of requirement. We are coy about
507 // the actual numbers, in case grades aren't released to
508 // students.
509 if (is_null($minmax->min) && is_null($minmax->max)) {
510 $string = 'any';
511 } else if (is_null($minmax->max)) {
512 $string = 'min';
513 } else if (is_null($minmax->min)) {
514 $string = 'max';
515 } else {
516 $string = 'range';
518 $information .= get_string('requires_grade_'.$string, 'condition', $minmax->name).' ';
523 // Test dates
524 if ($this->cm->availablefrom) {
525 if (time() < $this->cm->availablefrom) {
526 $available = false;
528 $information .= get_string('requires_date', 'condition',
529 self::show_time($this->cm->availablefrom,
530 self::is_midnight($this->cm->availablefrom)));
534 if ($this->cm->availableuntil) {
535 if (time() >= $this->cm->availableuntil) {
536 $available = false;
537 // But we don't display any information about this case. This is
538 // because the only reason to set a 'disappear' date is usually
539 // to get rid of outdated information/clutter in which case there
540 // is no point in showing it...
542 // Note it would be nice if we could make it so that the 'until'
543 // date appears below the item while the item is still accessible,
544 // unfortunately this is not possible in the current system. Maybe
545 // later, or if somebody else wants to add it.
549 $information=trim($information);
550 return $available;
554 * Shows a time either as a date or a full date and time, according to
555 * user's timezone.
556 * @param int $time Time
557 * @param bool $dateonly If true, uses date only
558 * @return string Date
560 private function show_time($time, $dateonly) {
561 return userdate($time,
562 get_string($dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
566 * @return bool True if information about availability should be shown to
567 * normal users
568 * @throws coding_exception If data wasn't loaded
570 public function show_availability() {
571 $this->require_data();
572 return $this->cm->showavailability;
576 * Internal function cheks that data was loaded.
578 * @return void throws coding_exception If data wasn't loaded
580 private function require_data() {
581 if (!$this->gotdata) {
582 throw new coding_exception('Error: cannot call when info was '.
583 'constructed without data');
588 * Obtains a grade score. Note that this score should not be displayed to
589 * the user, because gradebook rules might prohibit that. It may be a
590 * non-final score subject to adjustment later.
592 * @global object
593 * @global object
594 * @global object
595 * @param int $gradeitemid Grade item ID we're interested in
596 * @param bool $grabthelot If true, grabs all scores for current user on
597 * this course, so that later ones come from cache
598 * @param int $userid Set if requesting grade for a different user (does
599 * not use cache)
600 * @return float Grade score as a percentage in range 0-100 (e.g. 100.0
601 * or 37.21), or false if user does not have a grade yet
603 private function get_cached_grade_score($gradeitemid, $grabthelot=false, $userid=0) {
604 global $USER, $DB, $SESSION;
605 if ($userid==0 || $userid==$USER->id) {
606 // For current user, go via cache in session
607 if (empty($SESSION->gradescorecache) || $SESSION->gradescorecacheuserid!=$USER->id) {
608 $SESSION->gradescorecache = array();
609 $SESSION->gradescorecacheuserid = $USER->id;
611 if (!array_key_exists($gradeitemid, $SESSION->gradescorecache)) {
612 if ($grabthelot) {
613 // Get all grades for the current course
614 $rs = $DB->get_recordset_sql("
615 SELECT
616 gi.id,gg.finalgrade,gg.rawgrademin,gg.rawgrademax
617 FROM
618 {grade_items} gi
619 LEFT JOIN {grade_grades} gg ON gi.id=gg.itemid AND gg.userid=?
620 WHERE
621 gi.courseid=?", array($USER->id, $this->cm->course));
622 foreach ($rs as $record) {
623 $SESSION->gradescorecache[$record->id] =
624 is_null($record->finalgrade)
625 // No grade = false
626 ? false
627 // Otherwise convert grade to percentage
628 : (($record->finalgrade - $record->rawgrademin) * 100) /
629 ($record->rawgrademax - $record->rawgrademin);
632 $rs->close();
633 // And if it's still not set, well it doesn't exist (eg
634 // maybe the user set it as a condition, then deleted the
635 // grade item) so we call it false
636 if (!array_key_exists($gradeitemid, $SESSION->gradescorecache)) {
637 $SESSION->gradescorecache[$gradeitemid] = false;
639 } else {
640 // Just get current grade
641 $record = $DB->get_record('grade_grades', array(
642 'userid'=>$USER->id, 'itemid'=>$gradeitemid));
643 if ($record && !is_null($record->finalgrade)) {
644 $score = (($record->finalgrade - $record->rawgrademin) * 100) /
645 ($record->rawgrademax - $record->rawgrademin);
646 } else {
647 // Treat the case where row exists but is null, same as
648 // case where row doesn't exist
649 $score = false;
651 $SESSION->gradescorecache[$gradeitemid]=$score;
654 return $SESSION->gradescorecache[$gradeitemid];
655 } else {
656 // Not the current user, so request the score individually
657 $record = $DB->get_record('grade_grades', array(
658 'userid'=>$userid, 'itemid'=>$gradeitemid));
659 if ($record && !is_null($record->finalgrade)) {
660 $score = (($record->finalgrade - $record->rawgrademin) * 100) /
661 ($record->rawgrademax - $record->rawgrademin);
662 } else {
663 // Treat the case where row exists but is null, same as
664 // case where row doesn't exist
665 $score = false;
667 return $score;
672 * For testing only. Wipes information cached in user session.
674 * @global object
676 static function wipe_session_cache() {
677 global $SESSION;
678 unset($SESSION->gradescorecache);
679 unset($SESSION->gradescorecacheuserid);
683 * Utility function called by modedit.php; updates the
684 * course_modules_availability table based on the module form data.
686 * @param object $cm Course-module with as much data as necessary, min id
687 * @param object $fromform
688 * @param bool $wipefirst Defaults to true
690 public static function update_cm_from_form($cm, $fromform, $wipefirst=true) {
691 $ci=new condition_info($cm, CONDITION_MISSING_EVERYTHING, false);
692 if ($wipefirst) {
693 $ci->wipe_conditions();
695 foreach ($fromform->conditiongradegroup as $record) {
696 if($record['conditiongradeitemid']) {
697 $ci->add_grade_condition($record['conditiongradeitemid'],
698 $record['conditiongrademin'],$record['conditiongrademax']);
701 if(isset ($fromform->conditioncompletiongroup)) {
702 foreach($fromform->conditioncompletiongroup as $record) {
703 if($record['conditionsourcecmid']) {
704 $ci->add_completion_condition($record['conditionsourcecmid'],
705 $record['conditionrequiredcompletion']);
712 * Used in course/lib.php because we need to disable the completion JS if
713 * a completion value affects a conditional activity.
715 * @global object
716 * @param object $course Moodle course object
717 * @param object $cm Moodle course-module
718 * @return bool True if this is used in a condition, false otherwise
720 public static function completion_value_used_as_condition($course, $cm) {
721 // Have we already worked out a list of required completion values
722 // for this course? If so just use that
723 global $CONDITIONLIB_PRIVATE;
724 if (!array_key_exists($course->id, $CONDITIONLIB_PRIVATE->usedincondition)) {
725 // We don't have data for this course, build it
726 $modinfo = get_fast_modinfo($course);
727 $CONDITIONLIB_PRIVATE->usedincondition[$course->id] = array();
728 foreach ($modinfo->cms as $othercm) {
729 foreach ($othercm->conditionscompletion as $cmid=>$expectedcompletion) {
730 $CONDITIONLIB_PRIVATE->usedincondition[$course->id][$cmid] = true;
734 return array_key_exists($cm->id, $CONDITIONLIB_PRIVATE->usedincondition[$course->id]);