MDL-44070 Conditional availability enhancements (5): deprecate old lib
authorsam marshall <s.marshall@open.ac.uk>
Tue, 11 Mar 2014 16:42:59 +0000 (16:42 +0000)
committersam marshall <s.marshall@open.ac.uk>
Mon, 7 Apr 2014 19:11:45 +0000 (20:11 +0100)
The old conditionlib.php, which is replaced by the new availability
API, has been deprecated.

* Code which uses the key functions (is_available,
  get_full_information) should still work. These now show
  deprecated warnings and then pass through to equivalents in the
  new API.
* I have created new unit tests for these functions.
* The old language file has been removed (reused strings already
  moved with AMOS).
* Most other functions throw exceptions because it was impossible
  (due to fundamental API differences) or difficult to reimplement.
* I don't really expect that non-core code (outside unit tests) will
  have used any of the other functions.

lang/en/condition.php [deleted file]
lib/classes/component.php
lib/conditionlib.php
lib/tests/conditionlib_test.php

diff --git a/lang/en/condition.php b/lang/en/condition.php
deleted file mode 100644 (file)
index f6af598..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// 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.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Strings for component 'condition', language 'en', branch 'MOODLE_20_STABLE'
- *
- * @package   condition
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-$string['addcompletions'] = 'Add {no} activity conditions to form';
-$string['addgrades'] = 'Add {no} grade conditions to form';
-$string['adduserfields'] = 'Add {no} user field conditions to form';
-$string['availabilityconditions'] = 'Restrict access';
-$string['availablefrom'] = 'Allow access from';
-$string['availablefrom_help'] = 'Access from/to dates determine when students can access the activity via a link on the course page.
-
-The difference between access from/to dates and availability settings for the activity is that outside the set dates, access from/to prevents access completely, while availability allows students to view the activity description.';
-$string['availableuntil'] = 'Allow access until';
-$string['badavailabledates'] = 'Invalid dates. If you set both dates, the \'Allow access from\' date should be before the \'until\' date.';
-$string['badgradelimits'] = 'If you set both an upper and lower grade limit, the upper limit must be higher than the lower limit.';
-$string['completion_complete'] = 'must be marked complete';
-$string['completioncondition'] = 'Activity completion condition';
-$string['completioncondition_help'] = 'This setting determines any activity completion conditions which must be met in order to access the activity. Note that completion tracking must first be set before an activity completion condition can be set.
-
-Multiple activity completion conditions may be set if desired.  If so, access to the activity will only be permitted when ALL activity completion conditions are met.';
-$string['completionconditionsection'] = 'Activity completion condition';
-$string['completionconditionsection_help'] = 'This setting determines any activity completion conditions which must be met in order to access the section. Note that completion tracking must first be set before an activity completion condition can be set.
-
-Multiple activity completion conditions may be set if desired.  If so, access to the section will only be permitted when ALL activity completion conditions are met.';
-$string['completion_fail'] = 'must be complete with fail grade';
-$string['completion_incomplete'] = 'must not be marked complete';
-$string['completion_pass'] = 'must be complete with pass grade';
-$string['configenableavailability'] = 'When enabled, this lets you set conditions (based on date, grade, or completion) that control whether an activity or resource can be accessed.';
-$string['contains'] = 'contains';
-$string['doesnotcontain'] = 'doesn\'t contain';
-$string['enableavailability'] = 'Enable conditional access';
-$string['endswith'] = 'ends with';
-$string['fielddeclaredmultipletimes'] = 'You can not declare the same field more than once per activity.';
-$string['grade_atleast'] = 'must be at least';
-$string['gradecondition'] = 'Grade condition';
-$string['gradecondition_help'] = 'This setting determines any grade conditions which must be met in order to access the activity.
-
-Multiple grade conditions may be set if desired. If so, the activity will only allow access when ALL grade conditions are met.';
-$string['gradeconditionsection'] = 'Grade condition';
-$string['gradeconditionsection_help'] = 'This setting determines any grade conditions which must be met in order to access the section.
-
-Multiple grade conditions may be set if desired. If so, the section will only allow access when ALL grade conditions are met.';
-$string['grade_upto'] = 'and less than';
-$string['gradeitembutnolimits'] = 'You must enter an upper or lower limit, or both.';
-$string['gradelimitsbutnoitem'] = 'You must choose a grade item.';
-$string['gradesmustbenumeric'] = 'The minimum and maximum grades must be numeric (or blank).';
-$string['isempty'] = 'is empty';
-$string['isequalto'] = 'is equal to';
-$string['isnotempty'] = 'is not empty';
-$string['none'] = '(none)';
-$string['notavailableyet'] = 'Not available yet';
-$string['requires_completion_0'] = 'Not available unless the activity <strong>{$a}</strong> is incomplete.';
-$string['requires_completion_1'] = 'Not available until the activity <strong>{$a}</strong> is marked complete.';
-$string['requires_completion_2'] = 'Not available until the activity <strong>{$a}</strong> is complete and passed.';
-$string['requires_completion_3'] = 'Not available unless the activity <strong>{$a}</strong> is complete and failed.';
-$string['requires_date'] = 'Available from {$a}.';
-$string['requires_date_before'] = 'Available until {$a}.';
-$string['requires_date_both'] = 'Available from {$a->from} to {$a->until}.';
-$string['requires_date_both_single_day'] = 'Available on {$a}.';
-$string['requires_grade_any'] = 'Not available until you have a grade in <strong>{$a}</strong>.';
-$string['requires_grade_max'] = 'Not available unless you get an appropriate score in <strong>{$a}</strong>.';
-$string['requires_grade_min'] = 'Not available until you achieve a required score in <strong>{$a}</strong>.';
-$string['requires_grade_range'] = 'Not available unless you get a particular score in <strong>{$a}</strong>.';
-$string['requires_user_field_contains'] = 'Not available unless your <strong>{$a->field}</strong> contains <strong>{$a->value}</strong>.';
-$string['requires_user_field_doesnotcontain'] = 'Not available if your <strong>{$a->field}</strong> contains <strong>{$a->value}</strong>.';
-$string['requires_user_field_endswith'] = 'Not available unless your <strong>{$a->field}</strong> ends with <strong>{$a->value}</strong>.';
-$string['requires_user_field_isempty'] = 'Not available unless your <strong>{$a->field}</strong> is empty.';
-$string['requires_user_field_isequalto'] = 'Not available unless your <strong>{$a->field}</strong> is equal to <strong>{$a->value}</strong>.';
-$string['requires_user_field_isnotempty'] = 'Not available if your <strong>{$a->field}</strong> is empty.';
-$string['requires_user_field_startswith'] = 'Not available unless your <strong>{$a->field}</strong> starts withs <strong>{$a->value}</strong>.';
-$string['showavailability'] = 'While access is prevented';
-$string['showavailabilitysection'] = 'Before section can be accessed';
-$string['showavailability_hide'] = 'Hide activity entirely in the course and gradebook';
-$string['showavailability_show'] = 'Show activity greyed-out, with restriction information';
-$string['showavailabilitysection_hide'] = 'Hide section entirely';
-$string['showavailabilitysection_show'] = 'Show section greyed-out, with restriction information';
-$string['startswith'] = 'starts with';
-$string['userfield'] = 'User field';
-$string['userfield_help'] = 'You can restrict access based on any field from the users profile.';
-$string['userrestriction_hidden'] = 'Restricted (completely hidden, no message): {$a}';
-$string['userrestriction_visible'] = 'Restricted: {$a}';
-$string['groupingnoaccess'] = 'You do not currently belong to a group which has access to this section. ';
index a08c4f7..d990abf 100644 (file)
@@ -321,7 +321,6 @@ $cache = '.var_export($cache, true).';
             'cache'       => $CFG->dirroot.'/cache',
             'calendar'    => $CFG->dirroot.'/calendar',
             'cohort'      => $CFG->dirroot.'/cohort',
-            'condition'   => null,
             'completion'  => null,
             'countries'   => null,
             'course'      => $CFG->dirroot.'/course',
index 3b4b9d7..499cfee 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Used for tracking conditions that apply before activities are displayed
- * to students ('conditional availability').
+ * Used to be used for tracking conditions that apply before activities are
+ * displayed to students ('conditional availability').
  *
- * @package    core_condition
- * @category   condition
- * @copyright  1999 onwards Martin Dougiamas  http://dougiamas.com
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * Now replaced by the availability API. This library is a stub; some functions
+ * still work while others throw exceptions. New code should not rely on the
+ * classes, functions, or constants defined here.
+ *
+ * @package core_availability
+ * @copyright 2014 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @deprecated Since Moodle 2.7
  */
 
 defined('MOODLE_INTERNAL') || die();
@@ -87,12 +91,16 @@ define('OP_IS_NOT_EMPTY', 'isnotempty');
 require_once($CFG->libdir.'/completionlib.php');
 
 /**
- * Core class to handle conditional activites
+ * Core class to handle conditional activities.
  *
- * @package   core_condition
- * @category  condition
- * @copyright 2012 The Open University
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * This class is now deprecated and partially functional. Public functions either
+ * work and output deprecated messages or (in the case of the more obscure ones
+ * which weren't really for public use, or those which can't be implemented in
+ * the new API) throw exceptions.
+ *
+ * @copyright 2014 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @deprecated Since Moodle 2.7
  */
 class condition_info extends condition_info_base {
     /**
@@ -100,22 +108,42 @@ class condition_info extends condition_info_base {
      *
      * @global moodle_database $DB
      * @uses CONDITION_MISSING_NOTHING
-     * @param object $cm Moodle course-module object. May have extra fields
-     *   ->conditionsgrade, ->conditionscompletion which should come from
-     *   get_fast_modinfo. Should have ->availablefrom, ->availableuntil,
-     *   and ->showavailability, ->course, ->visible; but the only required
-     *   thing is ->id.
+     * @param object $cm Moodle course-module object. Required ->id, ->course
+     *   will save time, using a full cm_info will save more time
      * @param int $expectingmissing Used to control whether or not a developer
      *   debugging message (performance warning) will be displayed if some of
      *   the above data is missing and needs to be retrieved; a
      *   CONDITION_MISSING_xx constant
      * @param bool $loaddata If you need a 'write-only' object, set this value
      *   to false to prevent database access from constructor
+     * @deprecated Since Moodle 2.7
      */
     public function __construct($cm, $expectingmissing = CONDITION_MISSING_NOTHING,
-        $loaddata=true) {
-        parent::__construct($cm, 'course_modules', 'coursemoduleid',
-                $expectingmissing, $loaddata);
+            $loaddata=true) {
+        global $DB;
+        debugging('The condition_info class is deprecated; change to \core_availability\info_module',
+                DEBUG_DEVELOPER);
+
+        // Check ID as otherwise we can't do the other queries.
+        if (empty($cm->id)) {
+            throw new coding_exception('Invalid parameters; item ID not included');
+        }
+
+        // Load cm_info object.
+        if (!($cm instanceof cm_info)) {
+            // Get modinfo.
+            if (empty($cm->course)) {
+                $modinfo = get_fast_modinfo(
+                        $DB->get_field('course_modules', 'course', array('id' => $cm->id), MUST_EXIST));
+            } else {
+                $modinfo = get_fast_modinfo($cm->course);
+            }
+
+            // Get $cm object.
+            $cm = $modinfo->get_cm($cm->id);
+        }
+
+        $this->item = $cm;
     }
 
     /**
@@ -126,70 +154,55 @@ class condition_info extends condition_info_base {
      * dynamically.
      *
      * @param object $cm Moodle course-module data object
+     * @deprecated Since Moodle 2.7 (does nothing)
      */
     public static function fill_availability_conditions($cm) {
-        parent::fill_availability_conditions_inner($cm, 'course_modules', 'coursemoduleid');
+        debugging('Calls to condition_info::fill_availability_conditions should be removed',
+                DEBUG_DEVELOPER);
     }
 
     /**
      * Gets the course-module object with full necessary data to determine availability.
+     *
      * @return object Course-module object with full data
-     * @throws coding_exception If data was not supplied when constructing object
+     * @deprecated Since Moodle 2.7
      */
     public function get_full_course_module() {
-        return $this->get_full_item();
+        debugging('Calls to condition_info::get_full_course_module should be removed',
+                DEBUG_DEVELOPER);
+        return $this->item;
     }
 
     /**
-     * Utility function called by modedit.php; updates the
-     * course_modules_availability table based on the module form data.
+     * Used to update a table (which no longer exists) based on form data
+     * (which is no longer used).
+     *
+     * Should only have been called from core code. Now removed (throws exception).
      *
      * @param object $cm Course-module with as much data as necessary, min id
      * @param object $fromform Data from form
      * @param bool $wipefirst If true, wipes existing conditions
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function update_cm_from_form($cm, $fromform, $wipefirst=true) {
-        $ci = new condition_info($cm, CONDITION_MISSING_EVERYTHING, false);
-        parent::update_from_form($ci, $fromform, $wipefirst);
+        throw new coding_exception('Function no longer available');
     }
 
     /**
-     * Used in course/lib.php because we need to disable the completion JS if
-     * a completion value affects a conditional activity.
+     * Used to be used in course/lib.php because we needed to disable the
+     * completion JS if a completion value affects a conditional activity.
+     *
+     * Should only have been called from core code. Now removed (throws exception).
      *
      * @global stdClass $CONDITIONLIB_PRIVATE
      * @param object $course Moodle course object
      * @param object $item Moodle course-module
-     * @return bool True if this is used in a condition, false otherwise
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function completion_value_used_as_condition($course, $cm) {
-        // Have we already worked out a list of required completion values
-        // for this course? If so just use that
-        global $CONDITIONLIB_PRIVATE, $DB;
-        if (!array_key_exists($course->id, $CONDITIONLIB_PRIVATE->usedincondition)) {
-            // We don't have data for this course, build it
-            $modinfo = get_fast_modinfo($course);
-            $CONDITIONLIB_PRIVATE->usedincondition[$course->id] = array();
-
-            // Activities
-            foreach ($modinfo->cms as $othercm) {
-                foreach ($othercm->conditionscompletion as $cmid => $expectedcompletion) {
-                    $CONDITIONLIB_PRIVATE->usedincondition[$course->id][$cmid] = true;
-                }
-            }
-
-            // Sections
-            foreach ($modinfo->get_section_info_all() as $section) {
-                foreach ($section->conditionscompletion as $cmid => $expectedcompletion) {
-                    $CONDITIONLIB_PRIVATE->usedincondition[$course->id][$cmid] = true;
-                }
-            }
-        }
-        return array_key_exists($cm->id, $CONDITIONLIB_PRIVATE->usedincondition[$course->id]);
-    }
-
-    protected function get_context() {
-        return context_module::instance($this->item->id);
+        throw new coding_exception('Function no longer available');
     }
 }
 
@@ -197,10 +210,14 @@ class condition_info extends condition_info_base {
 /**
  * Handles conditional access to sections.
  *
- * @package   core_condition
- * @category  condition
- * @copyright 2012 The Open University
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * This class is now deprecated and partially functional. Public functions either
+ * work and output deprecated messages or (in the case of the more obscure ones
+ * which weren't really for public use, or those which can't be implemented in
+ * the new API) throw exceptions.
+ *
+ * @copyright 2014 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @deprecated Since Moodle 2.7
  */
 class condition_info_section extends condition_info_base {
     /**
@@ -208,21 +225,47 @@ class condition_info_section extends condition_info_base {
      *
      * @global moodle_database $DB
      * @uses CONDITION_MISSING_NOTHING
-     * @param object $section Moodle section object. May have extra fields
-     *   ->conditionsgrade, ->conditionscompletion. Should have ->availablefrom,
-     *   ->availableuntil, and ->showavailability, ->course; but the only
-     *   required thing is ->id.
+     * @param object $section Moodle section object. Required ->id, ->course
+     *   will save time, using a full section_info will save more time
      * @param int $expectingmissing Used to control whether or not a developer
      *   debugging message (performance warning) will be displayed if some of
      *   the above data is missing and needs to be retrieved; a
      *   CONDITION_MISSING_xx constant
      * @param bool $loaddata If you need a 'write-only' object, set this value
      *   to false to prevent database access from constructor
+     * @deprecated Since Moodle 2.7
      */
     public function __construct($section, $expectingmissing = CONDITION_MISSING_NOTHING,
-        $loaddata=true) {
-        parent::__construct($section, 'course_sections', 'coursesectionid',
-                $expectingmissing, $loaddata);
+            $loaddata=true) {
+        global $DB;
+        debugging('The condition_info_section class is deprecated; change to \core_availability\info_section',
+                DEBUG_DEVELOPER);
+
+        // Check ID as otherwise we can't do the other queries.
+        if (empty($section->id)) {
+            throw new coding_exception('Invalid parameters; item ID not included');
+        }
+
+        // Load cm_info object.
+        if (!($section instanceof section_info)) {
+            // Get modinfo.
+            if (empty($section->course)) {
+                $modinfo = get_fast_modinfo(
+                        $DB->get_field('course_sections', 'course', array('id' => $section->id), MUST_EXIST));
+            } else {
+                $modinfo = get_fast_modinfo($section->course);
+            }
+
+            // Get $cm object.
+            foreach ($modinfo->get_section_info_all() as $possible) {
+                if ($possible->id === $section->id) {
+                    $section = $possible;
+                    break;
+                }
+            }
+        }
+
+        $this->item = $section;
     }
 
     /**
@@ -233,377 +276,68 @@ class condition_info_section extends condition_info_base {
      * dynamically.
      *
      * @param object $section Moodle section data object
+     * @deprecated Since Moodle 2.7 (does nothing)
      */
     public static function fill_availability_conditions($section) {
-        parent::fill_availability_conditions_inner($section, 'course_sections', 'coursesectionid');
+        debugging('Calls to condition_info_section::fill_availability_conditions should be removed',
+                DEBUG_DEVELOPER);
     }
 
     /**
      * Gets the section object with full necessary data to determine availability.
-     * @return object Section object with full data
-     * @throws coding_exception If data was not supplied when constructing object
+     *
+     * @return section_info Section object with full data
+     * @deprecated Since Moodle 2.7
      */
     public function get_full_section() {
-        return $this->get_full_item();
-    }
-
-    /**
-     * Gets list of required fields from main table.
-     * @return array Array of field names
-     */
-    protected function get_main_table_fields() {
-        return array_merge(parent::get_main_table_fields(), array('groupingid'));
+        debugging('Calls to condition_info_section::get_full_section should be removed',
+                DEBUG_DEVELOPER);
+        return $this->item;
     }
 
     /**
-     * Determines whether this particular section is currently available
-     * according to these criteria.
+     * Utility function that used to be called by modedit.php; updated a
+     * table (that no longer exists) based on the module form data.
      *
-     * - This does not include the 'visible' setting (i.e. this might return
-     *   true even if visible is false); visible is handled independently.
-     * - This does not take account of the viewhiddenactivities capability.
-     *   That should apply later.
-     *
-     * @global moodle_database $DB
-     * @global stdclass $USER
-     * @param string $information If the item has availability restrictions,
-     *   a string that describes the conditions will be stored in this variable;
-     *   if this variable is set blank, that means don't display anything
-     * @param bool $grabthelot Performance hint: if true, caches information
-     *   required for all course-modules, to make the front page and similar
-     *   pages work more quickly (works only for current user)
-     * @param int $userid If set, specifies a different user ID to check availability for
-     * @param object $modinfo Usually leave as null for default. Specify when
-     *   calling recursively from inside get_fast_modinfo. The value supplied
-     *   here must include list of all CMs with 'id' and 'name'
-     * @return bool True if this item is available to the user, false otherwise
-     */
-    public function is_available(&$information, $grabthelot=false, $userid=0, $modinfo=null) {
-        global $DB, $USER, $CONDITIONLIB_PRIVATE;
-
-        $available = parent::is_available($information, $grabthelot, $userid, $modinfo);
-
-        // test if user is enrolled to a grouping which has access to the section
-        if (!empty($this->item->groupingid)) {
-            // Get real user id
-            if (!$userid) {
-                $userid = $USER->id;
-            }
-            $context = $this->get_context();
-
-            if ($userid != $USER->id) {
-                // We are requesting for a non-current user so check it individually
-                // (no cache). Do grouping check first, it's probably faster
-                // than the capability check
-                $gotit = $DB->record_exists_sql('
-                        SELECT
-                            1
-                        FROM
-                            {groupings} g
-                            JOIN {groupings_groups} gg ON g.id = gg.groupingid
-                            JOIN {groups_members} gm ON gg.groupid = gm.groupid
-                        WHERE
-                            g.id = ? AND gm.userid = ?',
-                        array($this->item->groupingid, $userid));
-                if (!$gotit && !has_capability('moodle/site:accessallgroups', $context, $userid)) {
-                    $available = false;
-                    $information .= get_string('groupingnoaccess', 'condition');
-                }
-            } else {
-                // Request is for current user - use cache
-                if( !array_key_exists($this->item->course, $CONDITIONLIB_PRIVATE->groupingscache)) {
-                    if (has_capability('moodle/site:accessallgroups', $context)) {
-                        $CONDITIONLIB_PRIVATE->groupingscache[$this->item->course] = true;
-                    } else {
-                        $groupings = $DB->get_records_sql('
-                                SELECT
-                                    g.id as gid
-                                FROM
-                                    {groupings} g
-                                    JOIN {groupings_groups} gg ON g.id = gg.groupingid
-                                    JOIN {groups_members} gm ON gg.groupid = gm.groupid
-                                WHERE
-                                    g.courseid = ? AND gm.userid = ?',
-                                array($this->item->course, $userid));
-                        $list = array();
-                        foreach ($groupings as $grouping) {
-                            $list[$grouping->gid] = true;
-                        }
-                        $CONDITIONLIB_PRIVATE->groupingscache[$this->item->course] = $list;
-                    }
-                }
-
-                $usergroupings = $CONDITIONLIB_PRIVATE->groupingscache[$this->item->course];
-                if ($usergroupings !== true && !array_key_exists($this->item->groupingid, $usergroupings)) {
-                    $available = false;
-                    $information .= get_string('groupingnoaccess', 'condition');
-                }
-            }
-        }
-
-        $information = trim($information);
-        return $available;
-    }
-
-    /**
-     * Utility function called by modedit.php; updates the
-     * course_modules_availability table based on the module form data.
+     * Should only have been called from core code. Now removed (throws exception).
      *
      * @param object $section Section object, must at minimum contain id
      * @param object $fromform Data from form
      * @param bool $wipefirst If true, wipes existing conditions
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function update_section_from_form($section, $fromform, $wipefirst=true) {
-        $ci = new condition_info_section($section, CONDITION_MISSING_EVERYTHING);
-        parent::update_from_form($ci, $fromform, $wipefirst);
-    }
-
-    protected function get_context() {
-        return context_course::instance($this->item->course);
+        throw new coding_exception('Function no longer available');
     }
 }
 
 
 /**
- * Base class to handle conditional items of some kind (currently either
- * course_modules or sections; they must have a corresponding _availability
- * table).
+ * Base class to handle conditional items (course_modules or sections).
+ *
+ * This class is now deprecated and partially functional. Public functions either
+ * work and output deprecated messages or (in the case of the more obscure ones
+ * which weren't really for public use, or those which can't be implemented in
+ * the new API) throw exceptions.
  *
- * @package   core_condition
- * @category  condition
  * @copyright 2012 The Open University
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @deprecated Since Moodle 2.7
  */
 abstract class condition_info_base {
+    /** @var cm_info|section_info Item with availability data */
     protected $item;
-    /** @var bool */
-    protected $gotdata;
-    /** @var string */
-    protected $availtable;
-    /** @var string */
-    protected $availfieldtable;
-    /** @var string */
-    protected $idfieldname;
-    /** @var array */
-    protected $usergroupings;
-    /** @var array An array of custom profile field ids => to their shortname */
-    protected $customprofilefields = null;
-    /**
-     * Constructs with item details.
-     *
-     * @global moodle_database $DB
-     * @uses CONDITION_MISSING_NOTHING
-     * @uses CONDITION_MISSING_EVERYTHING
-     * @uses CONDITION_MISSING_EXTRATABLE
-     * @uses DEBUG_DEVELOPER
-     * @param object $item Object representing some kind of item (cm or section).
-     *   May have extra fields ->conditionsgrade, ->conditionscompletion.
-     *   Should have ->availablefrom, ->availableuntil, and ->showavailability,
-     *   ->course; but the only required thing is ->id.
-     * @param string $tableprefix Prefix for table used to store availability
-     *   data, e.g. 'course_modules' if we are going to look at
-     *   course_modules_availability.
-     * @param string $idfield Within this table, name of field used as item id
-     *   (e.g. 'coursemoduleid')
-     * @param int $expectingmissing Used to control whether or not a developer
-     *   debugging message (performance warning) will be displayed if some of
-     *   the above data is missing and needs to be retrieved; a
-     *   CONDITION_MISSING_xx constant
-     * @param bool $loaddata If you need a 'write-only' object, set this value
-     *   to false to prevent database access from constructor
-     * @return condition_info Object which can retrieve information about the
-     *   activity
-     */
-    public function __construct($item, $tableprefix, $idfield, $expectingmissing, $loaddata) {
-        global $DB;
-
-        // Check ID as otherwise we can't do the other queries
-        if (empty($item->id)) {
-            throw new coding_exception('Invalid parameters; item ID not included');
-        }
-
-        // DB table to store availability conditions
-        $this->availtable = $tableprefix . '_availability';
-
-        // DB table to store availability conditions for user fields
-        $this->availfieldtable = $tableprefix . '_avail_fields';
-
-        // Name of module/section ID field in DB
-        $this->idfieldname = $idfield;
-
-        // If not loading data, don't do anything else
-        if (!$loaddata) {
-            $this->item = (object)array('id' => $item->id);
-            $this->gotdata = false;
-            return;
-        }
-
-        // Missing basic data from course_modules
-        $basicfields = $this->get_main_table_fields();
-        $missingbasicfields = false;
-        foreach ($basicfields as $field) {
-            if (!isset($item->{$field})) {
-                $missingbasicfields = true;
-                break;
-            }
-        }
-        if ($missingbasicfields) {
-            if ($expectingmissing<CONDITION_MISSING_EVERYTHING) {
-                debugging('Performance warning: condition_info constructor is ' .
-                        'faster if you pass in $item with at least basic fields ' .
-                        'from its table. '.
-                        '[This warning can be disabled, see phpdoc.]',
-                        DEBUG_DEVELOPER);
-            }
-            $item = $DB->get_record($tableprefix, array('id' => $item->id),
-                    implode(',', $basicfields), MUST_EXIST);
-        }
-
-        $this->item = clone($item);
-        $this->gotdata = true;
-
-        // Missing extra data
-        if (!isset($item->conditionsgrade) || !isset($item->conditionscompletion) || !isset($item->conditionsfield)) {
-            if ($expectingmissing<CONDITION_MISSING_EXTRATABLE) {
-                debugging('Performance warning: condition_info constructor is ' .
-                        'faster if you pass in a $item from get_fast_modinfo or ' .
-                        'the equivalent for sections. ' .
-                        '[This warning can be disabled, see phpdoc.]',
-                        DEBUG_DEVELOPER);
-            }
-
-            $this->fill_availability_conditions($this->item);
-        }
-    }
-
-    /**
-     * Gets list of required fields from main table.
-     *
-     * @return array Array of field names
-     */
-    protected function get_main_table_fields() {
-        return array('id', 'course', 'visible',
-                'availablefrom', 'availableuntil', 'showavailability');
-    }
-
-    /**
-     * Fills availability conditions into the item object, if they are missing,
-     * otherwise does nothing. Called by subclass fill_availability_conditions.
-     * @param object $item Item object
-     * @param string $tableprefix Prefix of name for _availability table e.g. 'course_modules'
-     * @param string $idfield Name of field that contains id e.g. 'coursemoduleid'
-     * @throws coding_exception If item object doesn't have id field
-     */
-    protected static function fill_availability_conditions_inner($item, $tableprefix, $idfield) {
-        global $DB, $CFG;
-        if (empty($item->id)) {
-            throw new coding_exception('Invalid parameters; item ID not included');
-        }
-
-        // Does nothing if the variables are already present
-        if (!isset($item->conditionsgrade) || !isset($item->conditionscompletion) || !isset($item->conditionsfield)) {
-            $item->conditionsgrade = array();
-            $item->conditionscompletion = array();
-            $item->conditionsfield = array();
-
-            $conditions = $DB->get_records_sql('
-                    SELECT
-                        a.id AS aid, gi.*, a.sourcecmid, a.requiredcompletion, a.gradeitemid,
-                        a.grademin as conditiongrademin, a.grademax as conditiongrademax
-                    FROM
-                        {' . $tableprefix . '_availability} a
-                        LEFT JOIN {grade_items} gi ON gi.id = a.gradeitemid
-                    WHERE ' . $idfield . ' = ?', array($item->id));
-            foreach ($conditions as $condition) {
-                if (!is_null($condition->sourcecmid)) {
-                    $item->conditionscompletion[$condition->sourcecmid] =
-                        $condition->requiredcompletion;
-                } else {
-                    $minmax = new stdClass;
-                    $minmax->min = $condition->conditiongrademin;
-                    $minmax->max = $condition->conditiongrademax;
-                    $minmax->name = self::get_grade_name($condition);
-                    $item->conditionsgrade[$condition->gradeitemid] = $minmax;
-                }
-            }
-
-            // For user fields
-            $sql = "SELECT a.id as cmaid, a.*, uf.*
-                      FROM {" . $tableprefix . "_avail_fields} a
-                 LEFT JOIN {user_info_field} uf ON a.customfieldid =  uf.id
-                     WHERE " . $idfield . " = :itemid";
-            $conditions = $DB->get_records_sql($sql, array('itemid' => $item->id));
-            foreach ($conditions as $condition) {
-                // If the custom field is not empty, then we have a custom profile field
-                if (!empty($condition->customfieldid)) {
-                    $field = $condition->customfieldid;
-                    // Check if the profile field name is not empty, if it is
-                    // then the custom profile field no longer exists, so
-                    // display !missing instead.
-                    if (!empty($condition->name)) {
-                        $fieldname = $condition->name;
-                    } else {
-                        $fieldname = '!missing';
-                    }
-                } else {
-                    $field = $condition->userfield;
-                    $fieldname = $condition->userfield;
-                }
-                $details = new stdClass;
-                $details->fieldname = $fieldname;
-                $details->operator = $condition->operator;
-                $details->value = $condition->value;
-                $item->conditionsfield[$field] = $details;
-            }
-        }
-    }
-
-    /**
-     * Obtains the name of a grade item.
-     *
-     * @global object $CFG
-     * @param object $gradeitemobj Object from get_record on grade_items table,
-     *     (can be empty if you want to just get !missing)
-     * @return string Name of item of !missing if it didn't exist
-     */
-    private static function get_grade_name($gradeitemobj) {
-        global $CFG;
-        if (isset($gradeitemobj->id)) {
-            require_once($CFG->libdir . '/gradelib.php');
-            $item = new grade_item;
-            grade_object::set_properties($item, $gradeitemobj);
-            return $item->get_name();
-        } else {
-            return '!missing'; // Ooops, missing grade
-        }
-    }
-
-    /**
-     * Gets the item object with full necessary data to determine availability.
-     * @return object Item object with full data
-     * @throws coding_exception If data was not supplied when constructing object
-     */
-    protected function get_full_item() {
-        $this->require_data();
-        return $this->item;
-    }
 
     /**
      * The operators that provide the relationship
      * between a field and a value.
      *
-     * @return array Associative array from operator constant to display name
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function get_condition_user_field_operators() {
-        return array(
-            OP_CONTAINS => get_string('contains', 'condition'),
-            OP_DOES_NOT_CONTAIN => get_string('doesnotcontain', 'condition'),
-            OP_IS_EQUAL_TO => get_string('isequalto', 'condition'),
-            OP_STARTS_WITH => get_string('startswith', 'condition'),
-            OP_ENDS_WITH => get_string('endswith', 'condition'),
-            OP_IS_EMPTY => get_string('isempty', 'condition'),
-            OP_IS_NOT_EMPTY => get_string('isnotempty', 'condition'),
-        );
+        throw new coding_exception('Function no longer available');
     }
 
     /**
@@ -615,100 +349,52 @@ abstract class condition_info_base {
      * text later.
      *
      * @param array $formatoptions Passed to format_string if provided
-     * @return array Associative array from user field constants to display name
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function get_condition_user_fields($formatoptions = null) {
-        global $DB;
-
-        $userfields = array(
-            'firstname' => get_user_field_name('firstname'),
-            'lastname' => get_user_field_name('lastname'),
-            'email' => get_user_field_name('email'),
-            'city' => get_user_field_name('city'),
-            'country' => get_user_field_name('country'),
-            'url' => get_user_field_name('url'),
-            'icq' => get_user_field_name('icq'),
-            'skype' => get_user_field_name('skype'),
-            'aim' => get_user_field_name('aim'),
-            'yahoo' => get_user_field_name('yahoo'),
-            'msn' => get_user_field_name('msn'),
-            'idnumber' => get_user_field_name('idnumber'),
-            'institution' => get_user_field_name('institution'),
-            'department' => get_user_field_name('department'),
-            'phone1' => get_user_field_name('phone1'),
-            'phone2' => get_user_field_name('phone2'),
-            'address' => get_user_field_name('address')
-        );
-
-        // Go through the custom profile fields now
-        if ($user_info_fields = $DB->get_records('user_info_field')) {
-            foreach ($user_info_fields as $field) {
-                if ($formatoptions) {
-                    $userfields[$field->id] = format_string($field->name, true, $formatoptions);
-                } else {
-                    $userfields[$field->id] = $field->name;
-                }
-            }
-        }
-
-        return $userfields;
+        throw new coding_exception('Function no longer available');
     }
 
     /**
      * Adds to the database a condition based on completion of another module.
      *
+     * Should only have been called from core and test code. Now removed
+     * (throws exception).
+     *
      * @global moodle_database $DB
      * @param int $cmid ID of other module
      * @param int $requiredcompletion COMPLETION_xx constant
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public function add_completion_condition($cmid, $requiredcompletion) {
-        global $DB;
-        // Add to DB
-        $DB->insert_record($this->availtable, (object)array(
-                $this->idfieldname => $this->item->id,
-                'sourcecmid' => $cmid, 'requiredcompletion' => $requiredcompletion),
-                false);
-
-        // Store in memory too
-        $this->item->conditionscompletion[$cmid] = $requiredcompletion;
+        throw new coding_exception('Function no longer available');
     }
 
     /**
      * Adds user fields condition
      *
+     * Should only have been called from core and test code. Now removed
+     * (throws exception).
+     *
      * @param mixed $field numeric if it is a user profile field, character
      *                     if it is a column in the user table
      * @param int $operator specifies the relationship between field and value
      * @param char $value the value of the field
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public function add_user_field_condition($field, $operator, $value) {
-        global $DB;
-
-        // Get the field name
-        $idfieldname = $this->idfieldname;
-
-        $objavailfield = new stdClass;
-        $objavailfield->$idfieldname = $this->item->id;
-        if (is_numeric($field)) { // If the condition field is numeric then it is a custom profile field
-            // Need to get the field name so we can add it to the cache
-            $ufield = $DB->get_field('user_info_field', 'name', array('id' => $field));
-            $objavailfield->fieldname = $ufield;
-            $objavailfield->customfieldid = $field;
-        } else {
-            $objavailfield->fieldname = $field;
-            $objavailfield->userfield = $field;
-        }
-        $objavailfield->operator = $operator;
-        $objavailfield->value = $value;
-        $DB->insert_record($this->availfieldtable, $objavailfield, false);
-
-        // Store in memory too
-        $this->item->conditionsfield[$field] = $objavailfield;
+        throw new coding_exception('Function no longer available');
     }
 
     /**
      * Adds to the database a condition based on the value of a grade item.
      *
+     * Should only have been called from core and test code. Now removed
+     * (throws exception).
+     *
      * @global moodle_database $DB
      * @param int $gradeitemid ID of grade item
      * @param float $min Minimum grade (>=), up to 5 decimal points, or null if none
@@ -716,47 +402,37 @@ abstract class condition_info_base {
      * @param bool $updateinmemory If true, updates data in memory; otherwise,
      *   memory version may be out of date (this has performance consequences,
      *   so don't do it unless it really needs updating)
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public function add_grade_condition($gradeitemid, $min, $max, $updateinmemory=false) {
-        global $DB;
-        // Normalise nulls
-        if ($min==='') {
-            $min = null;
-        }
-        if ($max==='') {
-            $max = null;
-        }
-        // Add to DB
-        $DB->insert_record($this->availtable, (object)array(
-                $this->idfieldname => $this->item->id,
-                'gradeitemid' => $gradeitemid, 'grademin' => $min, 'grademax' => $max),
-                false);
-
-        // Store in memory too
-        if ($updateinmemory) {
-            $this->item->conditionsgrade[$gradeitemid] = (object) array(
-                    'min' => $min, 'max' => $max);
-            $this->item->conditionsgrade[$gradeitemid]->name = self::get_grade_name(
-                    $DB->get_record('grade_items', array('id'=>$gradeitemid)));
-        }
+        throw new coding_exception('Function no longer available');
     }
 
-     /**
+    /**
      * Erases from the database all conditions for this activity.
      *
-     * @global moodle_database $DB
+     * Should only have been called from core and test code. Now removed
+     * (throws exception).
+     *
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public function wipe_conditions() {
-        // Wipe from DB
-        global $DB;
-
-        $DB->delete_records($this->availtable, array($this->idfieldname => $this->item->id));
-        $DB->delete_records($this->availfieldtable, array($this->idfieldname => $this->item->id));
+        throw new coding_exception('Function no longer available');
+    }
 
-        // And from memory
-        $this->item->conditionsgrade = array();
-        $this->item->conditionscompletion = array();
-        $this->item->conditionsfield = array();
+    /**
+     * Integration point with new API; obtains the new class for this item.
+     *
+     * @return \core_availability\info Availability info for item
+     */
+    protected function get_availability_info() {
+        if ($this->item instanceof section_info) {
+            return new \core_availability\info_section($this->item);
+        } else {
+            return new \core_availability\info_module($this->item);
+        }
     }
 
     /**
@@ -767,167 +443,13 @@ abstract class condition_info_base {
      *   calling recursively from inside get_fast_modinfo()
      * @return string Information string (for admin) about all restrictions on
      *   this item
+     * @deprecated Since Moodle 2.7
      */
     public function get_full_information($modinfo=null) {
-        $this->require_data();
-
-        $information = '';
-
-
-        // Completion conditions
-        if (count($this->item->conditionscompletion) > 0) {
-            if (!$modinfo) {
-                $modinfo = get_fast_modinfo($this->item->course);
-            }
-            foreach ($this->item->conditionscompletion as $cmid => $expectedcompletion) {
-                if (empty($modinfo->cms[$cmid])) {
-                    continue;
-                }
-                $information .= html_writer::start_tag('li');
-                $information .= get_string(
-                        'requires_completion_' . $expectedcompletion,
-                        'condition', $modinfo->cms[$cmid]->name) . ' ';
-                $information .= html_writer::end_tag('li');
-            }
-        }
-
-        // Grade conditions
-        if (count($this->item->conditionsgrade) > 0) {
-            foreach ($this->item->conditionsgrade as $gradeitemid => $minmax) {
-                // String depends on type of requirement. We are coy about
-                // the actual numbers, in case grades aren't released to
-                // students.
-                if (is_null($minmax->min) && is_null($minmax->max)) {
-                    $string = 'any';
-                } else if (is_null($minmax->max)) {
-                    $string = 'min';
-                } else if (is_null($minmax->min)) {
-                    $string = 'max';
-                } else {
-                    $string = 'range';
-                }
-                $information .= html_writer::start_tag('li');
-                $information .= get_string('requires_grade_'.$string, 'condition', $minmax->name).' ';
-                $information .= html_writer::end_tag('li');
-            }
-        }
-
-        // User field conditions
-        if (count($this->item->conditionsfield) > 0) {
-            $context = $this->get_context();
-            // Need the array of operators
-            foreach ($this->item->conditionsfield as $field => $details) {
-                $a = new stdclass;
-                // Display the fieldname into current lang.
-                if (is_numeric($field)) {
-                    // Is a custom profile field (will use multilang).
-                    $translatedfieldname = $details->fieldname;
-                } else {
-                    $translatedfieldname = get_user_field_name($details->fieldname);
-                }
-                $a->field = format_string($translatedfieldname, true, array('context' => $context));
-                $a->value = s($details->value);
-                $information .= html_writer::start_tag('li');
-                $information .= get_string('requires_user_field_'.$details->operator, 'condition', $a) . ' ';
-                $information .= html_writer::end_tag('li');
-            }
-        }
-
-        // The date logic is complicated. The intention of this logic is:
-        // 1) display date without time where possible (whenever the date is
-        //    midnight)
-        // 2) when the 'until' date is e.g. 00:00 on the 14th, we display it as
-        //    'until the 13th' (experience at the OU showed that students are
-        //    likely to interpret 'until <date>' as 'until the end of <date>').
-        // 3) This behaviour becomes confusing for 'same-day' dates where there
-        //    are some exceptions.
-        // Users in different time zones will typically not get the 'abbreviated'
-        // behaviour but it should work OK for them aside from that.
-
-        // The following cases are possible:
-        // a) From 13:05 on 14 Oct until 12:10 on 17 Oct (exact, exact)
-        // b) From 14 Oct until 12:11 on 17 Oct (midnight, exact)
-        // c) From 13:05 on 14 Oct until 17 Oct (exact, midnight 18 Oct)
-        // d) From 14 Oct until 17 Oct (midnight 14 Oct, midnight 18 Oct)
-        // e) On 14 Oct (midnight 14 Oct, midnight 15 Oct)
-        // f) From 13:05 on 14 Oct until 0:00 on 15 Oct (exact, midnight, same day)
-        // g) From 0:00 on 14 Oct until 12:05 on 14 Oct (midnight, exact, same day)
-        // h) From 13:05 on 14 Oct (exact)
-        // i) From 14 Oct (midnight)
-        // j) Until 13:05 on 14 Oct (exact)
-        // k) Until 14 Oct (midnight 15 Oct)
-
-        // Check if start and end dates are 'midnights', if so we show in short form
-        $shortfrom = self::is_midnight($this->item->availablefrom);
-        $shortuntil = self::is_midnight($this->item->availableuntil);
-
-        // For some checks and for display, we need the previous day for the 'until'
-        // value, if we are going to display it in short form
-        if ($this->item->availableuntil) {
-            $daybeforeuntil = strtotime('-1 day', usergetmidnight($this->item->availableuntil));
-        }
-
-        // Special case for if one but not both are exact and they are within a day
-        if ($this->item->availablefrom && $this->item->availableuntil &&
-                $shortfrom != $shortuntil && $daybeforeuntil < $this->item->availablefrom) {
-            // Don't use abbreviated version (see examples f, g above)
-            $shortfrom = false;
-            $shortuntil = false;
-        }
-
-        // When showing short end date, the display time is the 'day before' one
-        $displayuntil = $shortuntil ? $daybeforeuntil : $this->item->availableuntil;
-
-        if ($this->item->availablefrom && $this->item->availableuntil) {
-            if ($shortfrom && $shortuntil && $daybeforeuntil == $this->item->availablefrom) {
-                $information .= html_writer::start_tag('li');
-                $information .= get_string('requires_date_both_single_day', 'condition',
-                        self::show_time($this->item->availablefrom, true));
-                $information .= html_writer::end_tag('li');
-            } else {
-                $information .= html_writer::start_tag('li');
-                $information .= get_string('requires_date_both', 'condition', (object)array(
-                         'from' => self::show_time($this->item->availablefrom, $shortfrom),
-                         'until' => self::show_time($displayuntil, $shortuntil)));
-                $information .= html_writer::end_tag('li');
-            }
-        } else if ($this->item->availablefrom) {
-            $information .= html_writer::start_tag('li');
-            $information .= get_string('requires_date', 'condition',
-                self::show_time($this->item->availablefrom, $shortfrom));
-            $information .= html_writer::end_tag('li');
-        } else if ($this->item->availableuntil) {
-            $information .= html_writer::start_tag('li');
-            $information .= get_string('requires_date_before', 'condition',
-                self::show_time($displayuntil, $shortuntil));
-            $information .= html_writer::end_tag('li');
-        }
-
-        // The information is in <li> tags, but to avoid taking up more space
-        // if there is only a single item, we strip out the list tags so that it
-        // is plain text in that case.
-        if (!empty($information)) {
-            $li = strpos($information, '<li>', 4);
-            if ($li === false) {
-                $information = preg_replace('~^\s*<li>(.*)</li>\s*$~s', '$1', $information);
-            } else {
-                $information = html_writer::tag('ul', $information);
-            }
-            $information = trim($information);
-        }
-        return $information;
-    }
-
-    /**
-     * Checks whether a given time refers exactly to midnight (in current user
-     * timezone).
-     *
-     * @param int $time Time
-     * @return bool True if time refers to midnight, false if it's some other
-     *   time or if it is set to zero
-     */
-    private static function is_midnight($time) {
-        return $time && usergetmidnight($time) == $time;
+        debugging('condition_info*::get_full_information() is deprecated, replace ' .
+                'with new \core_availability\info_module($cm)->get_full_information()',
+                DEBUG_DEVELOPER);
+        return $this->get_availability_info()->get_full_information($modinfo);
     }
 
     /**
@@ -952,512 +474,65 @@ abstract class condition_info_base {
      * @param course_modinfo|null $modinfo Usually leave as null for default. Specify when
      *   calling recursively from inside get_fast_modinfo()
      * @return bool True if this item is available to the user, false otherwise
+     * @deprecated Since Moodle 2.7
      */
     public function is_available(&$information, $grabthelot=false, $userid=0, $modinfo=null) {
-        $this->require_data();
-
-        $available = true;
-        $information = '';
-
-        // Check each completion condition
-        if (count($this->item->conditionscompletion) > 0) {
-            if (!$modinfo) {
-                $modinfo = get_fast_modinfo($this->item->course);
-            }
-            $completion = new completion_info($modinfo->get_course());
-            foreach ($this->item->conditionscompletion as $cmid => $expectedcompletion) {
-                // If this depends on a deleted module, handle that situation
-                // gracefully.
-                if (empty($modinfo->cms[$cmid])) {
-                    global $PAGE;
-                    if (isset($PAGE) && strpos($PAGE->pagetype, 'course-view-')===0) {
-                        debugging("Warning: activity {$this->item->id} '{$this->item->name}' has condition " .
-                                "on deleted activity $cmid (to get rid of this message, edit the named activity)");
-                    }
-                    continue;
-                }
-
-                // The completion system caches its own data
-                $completiondata = $completion->get_data((object)array('id' => $cmid),
-                        $grabthelot, $userid, $modinfo);
-
-                $thisisok = true;
-                if ($expectedcompletion==COMPLETION_COMPLETE) {
-                    // 'Complete' also allows the pass, fail states
-                    switch ($completiondata->completionstate) {
-                        case COMPLETION_COMPLETE:
-                        case COMPLETION_COMPLETE_FAIL:
-                        case COMPLETION_COMPLETE_PASS:
-                            break;
-                        default:
-                            $thisisok = false;
-                    }
-                } else {
-                    // Other values require exact match
-                    if ($completiondata->completionstate!=$expectedcompletion) {
-                        $thisisok = false;
-                    }
-                }
-                if (!$thisisok) {
-                    $available = false;
-                    $information .= html_writer::start_tag('li');
-                    $information .= get_string(
-                        'requires_completion_' . $expectedcompletion,
-                        'condition', $modinfo->cms[$cmid]->name) . ' ';
-                    $information .= html_writer::end_tag('li');
-                }
-            }
-        }
-
-        // Check each grade condition
-        if (count($this->item->conditionsgrade)>0) {
-            foreach ($this->item->conditionsgrade as $gradeitemid => $minmax) {
-                $score = $this->get_cached_grade_score($gradeitemid, $grabthelot, $userid);
-                if ($score===false ||
-                        (!is_null($minmax->min) && $score<$minmax->min) ||
-                        (!is_null($minmax->max) && $score>=$minmax->max)) {
-                    // Grade fail
-                    $available = false;
-                    // String depends on type of requirement. We are coy about
-                    // the actual numbers, in case grades aren't released to
-                    // students.
-                    if (is_null($minmax->min) && is_null($minmax->max)) {
-                        $string = 'any';
-                    } else if (is_null($minmax->max)) {
-                        $string = 'min';
-                    } else if (is_null($minmax->min)) {
-                        $string = 'max';
-                    } else {
-                        $string = 'range';
-                    }
-                    $information .= html_writer::start_tag('li');
-                    $information .= get_string('requires_grade_' . $string, 'condition', $minmax->name) . ' ';
-                    $information .= html_writer::end_tag('li');
-                }
-            }
-        }
-
-        // Check if user field condition
-        if (count($this->item->conditionsfield) > 0) {
-            $context = $this->get_context();
-            foreach ($this->item->conditionsfield as $field => $details) {
-                $uservalue = $this->get_cached_user_profile_field($userid, $field);
-                if (!$this->is_field_condition_met($details->operator, $uservalue, $details->value)) {
-                    // Set available to false
-                    $available = false;
-                    // Display the fieldname into current lang.
-                    if (is_numeric($field)) {
-                        // Is a custom profile field (will use multilang).
-                        $translatedfieldname = $details->fieldname;
-                    } else {
-                        $translatedfieldname = get_user_field_name($details->fieldname);
-                    }
-                    $a = new stdClass();
-                    $a->field = format_string($translatedfieldname, true, array('context' => $context));
-                    $a->value = s($details->value);
-                    $information .= html_writer::start_tag('li');
-                    $information .= get_string('requires_user_field_'.$details->operator, 'condition', $a) . ' ';
-                    $information .= html_writer::end_tag('li');
-                }
-            }
-        }
-
-        // Test dates
-        if ($this->item->availablefrom) {
-            if (time() < $this->item->availablefrom) {
-                $available = false;
-
-                $information .= html_writer::start_tag('li');
-                $information .= get_string('requires_date', 'condition',
-                        self::show_time($this->item->availablefrom,
-                            self::is_midnight($this->item->availablefrom)));
-                $information .= html_writer::end_tag('li');
-            }
-        }
-
-        if ($this->item->availableuntil) {
-            if (time() >= $this->item->availableuntil) {
-                $available = false;
-                // But we don't display any information about this case. This is
-                // because the only reason to set a 'disappear' date is usually
-                // to get rid of outdated information/clutter in which case there
-                // is no point in showing it...
-
-                // Note it would be nice if we could make it so that the 'until'
-                // date appears below the item while the item is still accessible,
-                // unfortunately this is not possible in the current system. Maybe
-                // later, or if somebody else wants to add it.
-            }
-        }
-
-        // If the item is marked as 'not visible' then we don't change the available
-        // flag (visible/available are treated distinctly), but we remove any
-        // availability info. If the item is hidden with the eye icon, it doesn't
-        // make sense to show 'Available from <date>' or similar, because even
-        // when that date arrives it will still not be available unless somebody
-        // toggles the eye icon.
-        if (!$this->item->visible) {
-            $information = '';
-        }
-
-        // The information is in <li> tags, but to avoid taking up more space
-        // if there is only a single item, we strip out the list tags so that it
-        // is plain text in that case.
-        if (!empty($information)) {
-            $li = strpos($information, '<li>', 4);
-            if ($li === false) {
-                $information = preg_replace('~^\s*<li>(.*)</li>\s*$~s', '$1', $information);
-            } else {
-                $information = html_writer::tag('ul', $information);
-            }
-            $information = trim($information);
-        }
-        return $available;
-    }
-
-    /**
-     * Shows a time either as a date or a full date and time, according to
-     * user's timezone.
-     *
-     * @param int $time Time
-     * @param bool $dateonly If true, uses date only
-     * @return string Date
-     */
-    private function show_time($time, $dateonly) {
-        return userdate($time,
-                get_string($dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
+        debugging('condition_info*::is_available() is deprecated, replace ' .
+                'with new \core_availability\info_module($cm)->is_available()',
+                DEBUG_DEVELOPER);
+        return $this->get_availability_info()->is_available(
+                $information, $grabthelot, $userid, $modinfo);
     }
 
     /**
      * Checks whether availability information should be shown to normal users.
      *
+     * This information no longer makes sense with the new system because there
+     * are multiple show options. (I doubt anyone much used this function anyhow!)
+     *
      * @return bool True if information about availability should be shown to
      *   normal users
-     * @throws coding_exception If data wasn't loaded
+     * @deprecated Since Moodle 2.7
      */
     public function show_availability() {
-        $this->require_data();
-        return $this->item->showavailability;
-    }
-
-    /**
-     * Internal function cheks that data was loaded.
-     *
-     * @throws coding_exception If data wasn't loaded
-     */
-    private function require_data() {
-        if (!$this->gotdata) {
-            throw new coding_exception('Error: cannot call when info was ' .
-                'constructed without data');
-        }
-    }
-
-    /**
-     * Obtains a grade score. Note that this score should not be displayed to
-     * the user, because gradebook rules might prohibit that. It may be a
-     * non-final score subject to adjustment later.
-     *
-     * @global stdClass $USER
-     * @global moodle_database $DB
-     * @param int $gradeitemid Grade item ID we're interested in
-     * @param bool $grabthelot If true, grabs all scores for current user on
-     *   this course, so that later ones come from cache
-     * @param int $userid Set if requesting grade for a different user (does
-     *   not use cache)
-     * @return float Grade score as a percentage in range 0-100 (e.g. 100.0
-     *   or 37.21), or false if user does not have a grade yet
-     */
-    private function get_cached_grade_score($gradeitemid, $grabthelot=false, $userid=0) {
-        global $USER, $DB;
-        if (!$userid) {
-            $userid = $USER->id;
-        }
-        $cache = cache::make('core', 'gradecondition');
-        if (($cachedgrades = $cache->get($userid)) === false) {
-            $cachedgrades = array();
-        }
-        if (!array_key_exists($gradeitemid, $cachedgrades)) {
-            if ($grabthelot) {
-                // Get all grades for the current course
-                $rs = $DB->get_recordset_sql('
-                        SELECT
-                            gi.id,gg.finalgrade,gg.rawgrademin,gg.rawgrademax
-                        FROM
-                            {grade_items} gi
-                            LEFT JOIN {grade_grades} gg ON gi.id=gg.itemid AND gg.userid=?
-                        WHERE
-                            gi.courseid = ?', array($userid, $this->item->course));
-                foreach ($rs as $record) {
-                    $cachedgrades[$record->id] =
-                        is_null($record->finalgrade)
-                            // No grade = false
-                            ? false
-                            // Otherwise convert grade to percentage
-                            : (($record->finalgrade - $record->rawgrademin) * 100) /
-                                ($record->rawgrademax - $record->rawgrademin);
-
-                }
-                $rs->close();
-                // And if it's still not set, well it doesn't exist (eg
-                // maybe the user set it as a condition, then deleted the
-                // grade item) so we call it false
-                if (!array_key_exists($gradeitemid, $cachedgrades)) {
-                    $cachedgrades[$gradeitemid] = false;
-                }
-            } else {
-                // Just get current grade
-                $record = $DB->get_record('grade_grades', array(
-                    'userid'=>$userid, 'itemid'=>$gradeitemid));
-                if ($record && !is_null($record->finalgrade)) {
-                    $score = (($record->finalgrade - $record->rawgrademin) * 100) /
-                        ($record->rawgrademax - $record->rawgrademin);
-                } else {
-                    // Treat the case where row exists but is null, same as
-                    // case where row doesn't exist
-                    $score = false;
-                }
-                $cachedgrades[$gradeitemid]=$score;
-            }
-            $cache->set($userid, $cachedgrades);
-        }
-        return $cachedgrades[$gradeitemid];
+        debugging('condition_info*::show_availability() is deprecated and there ' .
+                'is no direct replacement (this is no longer a boolean value), ' .
+                'please refactor code',
+                DEBUG_DEVELOPER);
+        return false;
     }
 
     /**
-     * Called by grade code to inform the completion system when a grade has
-     * been changed. Grades can be used to determine condition for
-     * the course-module or section.
+     * Used to be called by grade code to inform the completion system when a
+     * grade was changed.
      *
-     * Note that this function may be called twice for one changed grade object.
+     * This function should not have ever been used outside the grade API, so
+     * it now just throws an exception.
      *
      * @param grade_grade $grade
      * @param bool $deleted
+     * @deprecated Since Moodle 2.7 (not available)
+     * @throws Always throws a coding_exception
      */
     public static function inform_grade_changed($grade, $deleted) {
-        cache::make('core', 'gradecondition')->delete($grade->userid);
+        throw new coding_exception('Function no longer available');
     }
 
     /**
-     * Returns true if a field meets the required conditions, false otherwise.
+     * Used to be used for testing.
      *
-     * @param string $operator the requirement/condition
-     * @param string $uservalue the user's value
-     * @param string $value the value required
-     * @return boolean
-     */
-    private function is_field_condition_met($operator, $uservalue, $value) {
-        if ($uservalue === false) {
-            // If the user value is false this is an instant fail.
-            // All user values come from the database as either data or the default.
-            // They will always be a string.
-            return false;
-        }
-        $fieldconditionmet = true;
-        // Just to be doubly sure it is a string.
-        $uservalue = (string)$uservalue;
-        switch($operator) {
-            case OP_CONTAINS: // contains
-                $pos = strpos($uservalue, $value);
-                if ($pos === false) {
-                    $fieldconditionmet = false;
-                }
-                break;
-            case OP_DOES_NOT_CONTAIN: // does not contain
-                if (!empty($value)) {
-                    $pos = strpos($uservalue, $value);
-                    if ($pos !== false) {
-                        $fieldconditionmet = false;
-                    }
-                }
-                break;
-            case OP_IS_EQUAL_TO: // equal to
-                if ($value !== $uservalue) {
-                    $fieldconditionmet = false;
-                }
-                break;
-            case OP_STARTS_WITH: // starts with
-                $length = strlen($value);
-                if ((substr($uservalue, 0, $length) !== $value)) {
-                    $fieldconditionmet = false;
-                }
-                break;
-            case OP_ENDS_WITH: // ends with
-                $length = strlen($value);
-                $start  = $length * -1; // negative
-                if (substr($uservalue, $start) !== $value) {
-                    $fieldconditionmet = false;
-                }
-                break;
-            case OP_IS_EMPTY: // is empty
-                if (!empty($uservalue)) {
-                    $fieldconditionmet = false;
-                }
-                break;
-            case OP_IS_NOT_EMPTY: // is not empty
-                if (empty($uservalue)) {
-                    $fieldconditionmet = false;
-                }
-                break;
-        }
-        return $fieldconditionmet;
-    }
-
-    /**
-     * Return the value for a user's profile field
-     *
-     * @param int $userid set if requesting grade for a different user (does not use cache)
-     * @param int $fieldid the user profile field id
-     * @return string the user value, or false if user does not have a user field value yet
-     */
-    protected function get_cached_user_profile_field($userid, $fieldid) {
-        global $USER, $DB, $CFG;
-
-        if ($userid === 0) {
-            // Map out userid = 0 to the current user
-            $userid = $USER->id;
-        }
-        $iscurrentuser = $USER->id == $userid;
-
-        if (isguestuser($userid) || ($iscurrentuser && !isloggedin())) {
-            // Must be logged in and can't be the guest. (e.g. front page)
-            return false;
-        }
-
-        // Custom profile fields will be numeric, there are no numeric standard profile fields so this is not a problem.
-        $iscustomprofilefield = is_numeric($fieldid);
-        if ($iscustomprofilefield) {
-            // As its a custom profile field we need to map the id back to the actual field.
-            // We'll also preload all of the other custom profile fields just in case and ensure we have the
-            // default value available as well.
-            if ($this->customprofilefields === null) {
-                $this->customprofilefields = $DB->get_records('user_info_field', null, 'sortorder ASC, id ASC', 'id, shortname, defaultdata');
-            }
-            if (!array_key_exists($fieldid, $this->customprofilefields)) {
-                // No such field exists.
-                // This shouldn't normally happen but occur if things go wrong when deleting a custom profile field
-                // or when restoring a backup of a course with user profile field conditions.
-                return false;
-            }
-            $field = $this->customprofilefields[$fieldid]->shortname;
-        } else {
-            $field = $fieldid;
-        }
-
-        // If its the current user than most likely we will be able to get this information from $USER.
-        // If its a regular profile field then it should already be available, if not then we have a mega problem.
-        // If its a custom profile field then it should be available but may not be. If it is then we use the value
-        // available, otherwise we load all custom profile fields into a temp object and refer to that.
-        // Noting its not going be great for performance if we have to use the temp object as it involves loading the
-        // custom profile field API and classes.
-        if ($iscurrentuser) {
-            if (!$iscustomprofilefield) {
-                if (property_exists($USER, $field)) {
-                    return $USER->{$field};
-                } else {
-                    // Unknown user field. This should not happen.
-                    throw new coding_exception('Requested user profile field does not exist');
-                }
-            }
-            // Checking if the custom profile fields are already available.
-            if (!isset($USER->profile)) {
-                // Drat! they're not. We need to use a temp object and load them.
-                // We don't use $USER as the profile fields are loaded into the object.
-                $user = new stdClass;
-                $user->id = $USER->id;
-                // This should ALWAYS be set, but just in case we check.
-                require_once($CFG->dirroot.'/user/profile/lib.php');
-                profile_load_custom_fields($user);
-                if (array_key_exists($field, $user->profile)) {
-                    return $user->profile[$field];
-                }
-            } else if (array_key_exists($field, $USER->profile)) {
-                // Hurrah they're available, this is easy.
-                return $USER->profile[$field];
-            }
-            // The profile field doesn't exist.
-            return false;
-        } else {
-            // Loading for another user.
-            if ($iscustomprofilefield) {
-                // Fetch the data for the field. Noting we keep this query simple so that Database caching takes care of performance
-                // for us (this will likely be hit again).
-                // We are able to do this because we've already pre-loaded the custom fields.
-                $data = $DB->get_field('user_info_data', 'data', array('userid' => $userid, 'fieldid' => $fieldid), IGNORE_MISSING);
-                // If we have data return that, otherwise return the default.
-                if ($data !== false) {
-                    return $data;
-                } else {
-                    return $this->customprofilefields[$field]->defaultdata;
-                }
-            } else {
-                // Its a standard field, retrieve it from the user.
-                return $DB->get_field('user', $field, array('id' => $userid), MUST_EXIST);
-            }
-        }
-        return false;
-    }
-
-    /**
-     * For testing only. Wipes information cached in cache.
-     * Replaced with {@link core_conditionlib_testcase::wipe_condition_cache()}
      * @deprecated since 2.6
      */
-    static function wipe_session_cache() {
-        cache::make('core', 'gradecondition')->purge();
+    public static function wipe_session_cache() {
+        debugging('Calls to completion_info::wipe_session_cache should be removed', DEBUG_DEVELOPER);
     }
 
     /**
      * Initialises the global cache
-     * @global stdClass $CONDITIONLIB_PRIVATE
-     */
-    public static function init_global_cache() {
-        global $CONDITIONLIB_PRIVATE;
-        $CONDITIONLIB_PRIVATE = new stdClass;
-        $CONDITIONLIB_PRIVATE->usedincondition = array();
-        $CONDITIONLIB_PRIVATE->groupingscache = array();
-    }
-
-    /**
-     * Utility function that resets grade/completion conditions in table based
-     * in data from editing form.
      *
-     * @param condition_info_base $ci Condition info
-     * @param object $fromform Data from form
-     * @param bool $wipefirst If true, wipes existing conditions
+     * @deprecated Since Moodle 2.7
      */
-    protected static function update_from_form(condition_info_base $ci, $fromform, $wipefirst) {
-        if ($wipefirst) {
-            $ci->wipe_conditions();
-        }
-        foreach ($fromform->conditiongradegroup as $record) {
-            if($record['conditiongradeitemid']) {
-                $ci->add_grade_condition($record['conditiongradeitemid'],
-                    unformat_float($record['conditiongrademin']), unformat_float($record['conditiongrademax']));
-            }
-        }
-        foreach ($fromform->conditionfieldgroup as $record) {
-            if($record['conditionfield']) {
-                $ci->add_user_field_condition($record['conditionfield'],
-                        $record['conditionfieldoperator'],
-                        $record['conditionfieldvalue']);
-            }
-        }
-        if(isset ($fromform->conditioncompletiongroup)) {
-            foreach($fromform->conditioncompletiongroup as $record) {
-                if($record['conditionsourcecmid']) {
-                    $ci->add_completion_condition($record['conditionsourcecmid'],
-                        $record['conditionrequiredcompletion']);
-                }
-            }
-        }
+    public static function init_global_cache() {
+        debugging('Calls to completion_info::init_globa_cache should be removed', DEBUG_DEVELOPER);
     }
-
-    /**
-     * Obtains context for any necessary checks.
-     *
-     * @return context Suitable context for the item
-     */
-    protected abstract function get_context();
 }
-
-condition_info::init_global_cache();
index e1a0b1a..f2b036b 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Tests for conditional activities.
+ * Tests for deprecated conditional activities classes.
  *
- * @package    core
- * @category   phpunit
- * @copyright  &copy; 2008 The Open University
- * @author     Sam Marshall
- * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package core_availability
+ * @copyright 2014 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  */
 
 defined('MOODLE_INTERNAL') || die();
@@ -30,6 +28,13 @@ global $CFG;
 require_once($CFG->dirroot . '/lib/conditionlib.php');
 
 
+/**
+ * Tests for deprecated conditional activities classes.
+ *
+ * @package core_availability
+ * @copyright 2014 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ */
 class core_conditionlib_testcase extends advanced_testcase {
 
     protected function setUp() {
@@ -44,761 +49,166 @@ class core_conditionlib_testcase extends advanced_testcase {
         $this->setUser($user);
     }
 
-    protected function wipe_condition_cache() {
-        cache::make('core', 'gradecondition')->purge();
-    }
-
     public function test_constructor() {
-        global $DB;
-        $cm = new stdClass;
-
-        // Test records.
-        $id = $DB->insert_record('course_modules', (object)array(
-            'showavailability'=>1, 'availablefrom'=>17, 'availableuntil'=>398, 'course'=>64));
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course();
+        $page = $generator->get_plugin_generator('mod_page')->create_instance(
+                array('course' => $course));
+        $modinfo = get_fast_modinfo($course);
 
         // No ID.
         try {
-            $test = new condition_info($cm);
+            $test = new condition_info((object)array());
             $this->fail();
         } catch (coding_exception $e) {
             // Do nothing.
+            $this->assertDebuggingCalled();
         }
 
+        // Get actual cm_info for comparison.
+        $realcm = $modinfo->get_cm($page->cmid);
+
         // No other data.
-        $cm->id = $id;
-        $test = new condition_info($cm, CONDITION_MISSING_EVERYTHING);
-        $this->assertEquals(
-            (object)array('id'=>$id, 'showavailability'=>1,
-                'availablefrom'=>17, 'availableuntil'=>398, 'course'=>64,
-                'conditionsgrade'=>array(), 'conditionscompletion'=>array(),
-                'visible' => 1, 'conditionsfield' => array()),
-            $test->get_full_course_module());
-
-        // Just the course_modules stuff, check it doesn't request that from db.
-        $cm->showavailability = 0;
-        $cm->availablefrom = 2;
-        $cm->availableuntil = 74;
-        $cm->course = 38;
-        $cm->visible = 1;
-        $test = new condition_info($cm, CONDITION_MISSING_EXTRATABLE);
-        $this->assertEquals(
-            (object)array('id'=>$id, 'showavailability'=>0,
-                'availablefrom'=>2, 'availableuntil'=>74, 'course'=>38,
-                'conditionsgrade' => array(), 'conditionscompletion' => array(),
-                'visible' => 1, 'conditionsfield' => array()),
-            $test->get_full_course_module());
-
-        // Now let's add some actual grade/completion conditions.
-        $DB->insert_record('course_modules_availability', (object)array(
-            'coursemoduleid'=>$id,
-            'sourcecmid'=>42,
-            'requiredcompletion'=>2
-        ));
-        $DB->insert_record('course_modules_availability', (object)array(
-            'coursemoduleid'=>$id,
-            'sourcecmid'=>666,
-            'requiredcompletion'=>1
-        ));
-        $DB->insert_record('course_modules_availability', (object)array(
-            'coursemoduleid'=>$id,
-            'gradeitemid'=>37,
-            'grademin'=>5.5
-        ));
-
-        $cm = (object)array('id'=>$id);
-        $test = new condition_info($cm, CONDITION_MISSING_EVERYTHING);
-        $fullcm = $test->get_full_course_module();
-        $this->assertEquals(array(42=>2, 666=>1), $fullcm->conditionscompletion);
-        $this->assertEquals(array(37=>(object)array('min'=>5.5, 'max'=>null, 'name'=>'!missing')),
-            $fullcm->conditionsgrade);
+        $test = new condition_info((object)array('id' => $page->cmid));
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realcm, $test->get_full_course_module());
+        $this->assertDebuggingCalled();
+
+        // Course id.
+        $test = new condition_info((object)array('id' => $page->cmid, 'course' => $course->id));
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realcm, $test->get_full_course_module());
+        $this->assertDebuggingCalled();
+
+        // Full cm.
+        $test = new condition_info($realcm);
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realcm, $test->get_full_course_module());
+        $this->assertDebuggingCalled();
     }
 
     /**
      * Same as above test but for course_sections instead of course_modules.
      */
     public function test_section_constructor() {
-        global $DB, $CFG;
-
-        // Test records.
-        $id = $DB->insert_record('course_sections', (object)array(
-                'showavailability' => 1, 'availablefrom' => 17,
-                'availableuntil' => 398, 'course' => 64, 'groupingid' => 13));
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course(
+                array('numsections' => 1), array('createsections' => true));
+        $modinfo = get_fast_modinfo($course);
 
         // No ID.
-        $section = new stdClass;
         try {
-            $test = new condition_info_section($section);
+            $test = new condition_info_section(((object)array()));
             $this->fail();
         } catch (coding_exception $e) {
             // Do nothing.
+            $this->assertDebuggingCalled();
         }
 
-        // No other data.
-        $section->id = $id;
-        $test = new condition_info_section($section, CONDITION_MISSING_EVERYTHING);
-        $this->assertEquals(
-                (object)array('id' => $id, 'showavailability' => 1, 'groupingid' => 13,
-                    'availablefrom' => 17, 'availableuntil' => 398, 'course' => 64,
-                    'conditionsgrade' => array(), 'conditionscompletion' => array(),
-                    'visible' => 1, 'conditionsfield' => array()),
-                $test->get_full_section());
-
-        // Just the course_sections stuff; check it doesn't request that from db
-        // (by using fake values and ensuring it still has those).
-        $section->showavailability = 0;
-        $section->availablefrom = 2;
-        $section->availableuntil = 74;
-        $section->course = 38;
-        $section->groupingid = 99;
-        $section->visible = 1;
-        $test = new condition_info_section($section, CONDITION_MISSING_EXTRATABLE);
-        $this->assertEquals(
-                (object)array('id' => $id, 'showavailability' => 0, 'groupingid' => 99,
-                    'availablefrom' => 2, 'availableuntil' => 74, 'course' => 38,
-                    'conditionsgrade' => array(), 'conditionscompletion' => array(),
-                    'visible' => 1, 'conditionsfield' => array()),
-                $test->get_full_section());
-
-        // Now let's add some actual grade/completion conditions.
-        $DB->insert_record('course_sections_availability', (object)array(
-                'coursesectionid' => $id,
-                'sourcecmid' => 42,
-                'requiredcompletion' => 2
-        ));
-        $DB->insert_record('course_sections_availability', (object)array(
-                'coursesectionid' => $id,
-                'sourcecmid' => 666,
-                'requiredcompletion' => 1
-        ));
-        $DB->insert_record('course_sections_availability', (object)array(
-                'coursesectionid' => $id,
-                'gradeitemid' => 37,
-                'grademin' => 5.5
-        ));
-
-        $section = (object)array('id' => $id);
-        $test = new condition_info_section($section, CONDITION_MISSING_EVERYTHING);
-        $fullsection = $test->get_full_section();
-        $this->assertEquals(array(42 => 2, 666 => 1), $fullsection->conditionscompletion);
-        $this->assertEquals(array(37 => (object)array('min' => 5.5, 'max' => null, 'name' => '!missing')),
-                $fullsection->conditionsgrade);
-    }
-
-    private function make_course() {
-        $category = $this->getDataGenerator()->create_category(array('name' => 'conditionlibtest'));
-        $course = $this->getDataGenerator()->create_course(
-                array('fullname' => 'Condition test',
-                    'shortname' => 'CT1',
-                    'category' => $category->id,
-                    'enablecompletion' => 1));
-        context_course::instance($course->id);
-        return $course->id;
-    }
-
-    private function make_course_module($courseid, $params = array()) {
-        global $DB;
-
-        $moduleid = $DB->get_field('modules', 'id', array('name'=>'resource'));
-
-        $rid = $DB->insert_record('resource', (object)array('course'=>$courseid,
-            'name'=>'xxx', 'alltext'=>'', 'popup'=>''));
-        $settings = (object)array(
-            'course'=>$courseid, 'module'=>$moduleid, 'instance'=>$rid);
-        foreach ($params as $name => $value) {
-            $settings->{$name} = $value;
-        }
-        $cmid = $DB->insert_record('course_modules', $settings);
-        rebuild_course_cache($courseid, true);
-        return $cmid;
-    }
-
-    private function make_section($courseid, $cmids, $sectionnum = 0, $params = array()) {
-        global $DB;
-        $record = (object)array(
-            'course' => $courseid,
-            'sequence' => implode(',', $cmids),
-            'section' => $sectionnum);
-        foreach ($params as $name => $value) {
-            $record->{$name} = $value;
-        }
-        $sectionid = $DB->insert_record('course_sections', $record);
-        foreach ($cmids as $cmid) {
-            $DB->update_record('course_modules', array('section' => $sectionid, 'id' => $cmid));
-        }
-        rebuild_course_cache($courseid, true);
-        return $sectionid;
-    }
-
-    private function make_grouping($courseid, $name) {
-        global $CFG;
-        require_once($CFG->dirroot . '/group/lib.php');
-        return groups_create_grouping((object)array('courseid' => $courseid,
-                'name' => $name));
-    }
-
-    private function make_group($courseid, $name, $groupingid = 0) {
-        global $CFG;
-        require_once($CFG->dirroot . '/group/lib.php');
-        $groupid = groups_create_group((object)array('courseid' => $courseid,
-                'name' => $name));
-        if ($groupingid) {
-            groups_assign_grouping($groupingid, $groupid);
-        }
-        return $groupid;
-    }
-
-    public function test_modinfo() {
-        global $DB;
-
-        // Let's make a course.
-        $courseid = $this->make_course();
-
-        // Now let's make a couple modules on that course.
-        $cmid1 = $this->make_course_module($courseid, array(
-            'showavailability'=>1, 'availablefrom'=>17, 'availableuntil'=>398,
-            'completion'=>COMPLETION_TRACKING_MANUAL));
-        $cmid2 = $this->make_course_module($courseid, array(
-            'showavailability'=>0, 'availablefrom'=>0, 'availableuntil'=>0));
-        $this->make_section($courseid, array($cmid1, $cmid2), 1);
-
-        // Add a fake grade item.
-        $gradeitemid = $DB->insert_record('grade_items', (object)array(
-            'courseid'=>$courseid, 'itemname'=>'frog'));
-
-        // One of the modules has grade and completion conditions, other doesn't.
-        $DB->insert_record('course_modules_availability', (object)array(
-            'coursemoduleid'=>$cmid2,
-            'sourcecmid'=>$cmid1,
-            'requiredcompletion'=>1
-        ));
-        $DB->insert_record('course_modules_availability', (object)array(
-            'coursemoduleid'=>$cmid2,
-            'gradeitemid'=>$gradeitemid,
-            'grademin'=>5.5
-        ));
-
-        // Okay sweet, now get modinfo.
-        $modinfo = get_fast_modinfo($courseid);
-
-        // Test basic data.
-        $this->assertEquals(1, $modinfo->cms[$cmid1]->showavailability);
-        $this->assertEquals(17, $modinfo->cms[$cmid1]->availablefrom);
-        $this->assertEquals(398, $modinfo->cms[$cmid1]->availableuntil);
-        $this->assertEquals(0, $modinfo->cms[$cmid2]->showavailability);
-        $this->assertEquals(0, $modinfo->cms[$cmid2]->availablefrom);
-        $this->assertEquals(0, $modinfo->cms[$cmid2]->availableuntil);
-
-        // Test condition arrays.
-        $this->assertEquals(array(), $modinfo->cms[$cmid1]->conditionscompletion);
-        $this->assertEquals(array(), $modinfo->cms[$cmid1]->conditionsgrade);
-        $this->assertEquals(array($cmid1=>1),
-            $modinfo->cms[$cmid2]->conditionscompletion);
-        $this->assertEquals(array($gradeitemid=>(object)array('min'=>5.5, 'max'=>null, 'name'=>'frog')),
-            $modinfo->cms[$cmid2]->conditionsgrade);
-    }
-
-    public function test_section_modinfo() {
-        global $DB;
-
-        // Let's make a course.
-        $courseid = $this->make_course();
-
-        // Now let's make a couple sections on that course, one of which has a cm.
-        $cmid = $this->make_course_module($courseid);
-        $sectionid1 = $this->make_section($courseid, array($cmid), 1, array(
-                'showavailability' => 1, 'availablefrom' => 17,
-                'availableuntil' => 398, 'groupingid' => 13));
-        $sectionid2 = $this->make_section($courseid, array(), 2);
-
-        // Add a fake grade item.
-        $gradeitemid = $DB->insert_record('grade_items', (object)array(
-                'courseid' => $courseid, 'itemname' => 'frog'));
-
-        // One of the sections has grade and completion conditions, other doesn't.
-        $DB->insert_record('course_sections_availability', (object)array(
-            'coursesectionid' => $sectionid2,
-            'sourcecmid' => $cmid,
-            'requiredcompletion'=>1
-        ));
-        $DB->insert_record('course_sections_availability', (object)array(
-            'coursesectionid' => $sectionid2,
-            'gradeitemid' => $gradeitemid,
-            'grademin' => 5.5
-        ));
-
-        rebuild_course_cache($courseid, true);
-        // Okay sweet, now get modinfo.
-        $modinfo = get_fast_modinfo($courseid);
-
-        // Test basic data.
-        $section1 = $modinfo->get_section_info(1);
-        $this->assertEquals(1, $section1->showavailability);
-        $this->assertEquals(17, $section1->availablefrom);
-        $this->assertEquals(398, $section1->availableuntil);
-        $this->assertEquals(13, $section1->groupingid);
-        $section2 = $modinfo->get_section_info(2);
-        $this->assertEquals(0, $section2->showavailability);
-        $this->assertEquals(0, $section2->availablefrom);
-        $this->assertEquals(0, $section2->availableuntil);
-        $this->assertEquals(0, $section2->groupingid);
-
-        // Test condition arrays.
-        $this->assertEquals(array(), $section1->conditionscompletion);
-        $this->assertEquals(array(), $section1->conditionsgrade);
-        $this->assertEquals(array($cmid => 1),
-                $section2->conditionscompletion);
-        $this->assertEquals(array($gradeitemid => (object)array('min' => 5.5, 'max' => null, 'name' => 'frog')),
-                $section2->conditionsgrade);
-    }
-
-    public function test_add_and_remove() {
-        global $DB;
-        // Make course and module.
-        $courseid = $this->make_course();
-        $cmid = $this->make_course_module($courseid, array(
-            'showavailability'=>0, 'availablefrom'=>0, 'availableuntil'=>0));
-        $this->make_section($courseid, array($cmid), 1);
-
-        // Check it has no conditions.
-        $test1 = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
-        $cm = $test1->get_full_course_module();
-        $this->assertEquals(array(), $cm->conditionscompletion);
-        $this->assertEquals(array(), $cm->conditionsgrade);
-
-        // Add conditions of each type.
-        $test1->add_completion_condition(13, 3);
-        $this->assertEquals(array(13=>3), $cm->conditionscompletion);
-        $test1->add_grade_condition(666, 0.4, null, true);
-        $this->assertEquals(array(666=>(object)array('min'=>0.4, 'max'=>null, 'name'=>'!missing')),
-            $cm->conditionsgrade);
-
-        // Check they were really added in db.
-        $test2 = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
-        $cm = $test2->get_full_course_module();
-        $this->assertEquals(array(13=>3), $cm->conditionscompletion);
-        $this->assertEquals(array(666=>(object)array('min'=>0.4, 'max'=>null, 'name'=>'!missing')),
-            $cm->conditionsgrade);
-
-        // Wipe conditions.
-        $test2->wipe_conditions();
-        $this->assertEquals(array(), $cm->conditionscompletion);
-        $this->assertEquals(array(), $cm->conditionsgrade);
-
-        // Check they were really wiped.
-        $test3 = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
-        $cm = $test3->get_full_course_module();
-        $this->assertEquals(array(), $cm->conditionscompletion);
-        $this->assertEquals(array(), $cm->conditionsgrade);
-    }
+        // Get actual cm_info for comparison.
+        $realsection = $modinfo->get_section_info(1);
 
-    public function test_section_add_and_remove() {
-        global $DB;
+        // No other data.
+        $test = new condition_info_section((object)array('id' => $realsection->id));
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realsection, $test->get_full_section());
+        $this->assertDebuggingCalled();
 
-        // Make course and module.
-        $courseid = $this->make_course();
-        $cmid = $this->make_course_module($courseid);
-        $sectionid = $this->make_section($courseid, array($cmid), 1);
+        // Course id.
+        $test = new condition_info_section((object)array('id' => $realsection->id,
+                'course' => $course->id));
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realsection, $test->get_full_section());
+        $this->assertDebuggingCalled();
 
-        // Check it has no conditions.
-        $test1 = new condition_info_section((object)array('id'=>$sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $section = $test1->get_full_section();
-        $this->assertEquals(array(), $section->conditionscompletion);
-        $this->assertEquals(array(), $section->conditionsgrade);
-
-        // Add conditions of each type.
-        $test1->add_completion_condition(13, 3);
-        $this->assertEquals(array(13 => 3), $section->conditionscompletion);
-        $test1->add_grade_condition(666, 0.4, null, true);
-        $this->assertEquals(array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing')),
-                $section->conditionsgrade);
-
-        // Check they were really added in db.
-        $test2 = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $section = $test2->get_full_section();
-        $this->assertEquals(array(13 => 3), $section->conditionscompletion);
-        $this->assertEquals(array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing')),
-                $section->conditionsgrade);
-
-        // Wipe conditions.
-        $test2->wipe_conditions();
-        $this->assertEquals(array(), $section->conditionscompletion);
-        $this->assertEquals(array(), $section->conditionsgrade);
-
-        // Check they were really wiped.
-        $test3 = new condition_info_section((object)array('id' => $cmid),
-                CONDITION_MISSING_EVERYTHING);
-        $section = $test3->get_full_section();
-        $this->assertEquals(array(), $section->conditionscompletion);
-        $this->assertEquals(array(), $section->conditionsgrade);
+        // Full object.
+        $test = new condition_info_section($realsection);
+        $this->assertDebuggingCalled();
+        $this->assertEquals($realsection, $test->get_full_section());
+        $this->assertDebuggingCalled();
     }
 
+    /**
+     * Tests the is_available function for modules. This does not test all the
+     * conditions and stuff, because it only needs to check that the system
+     * connects through to the real availability API. Also tests
+     * get_full_information function.
+     */
     public function test_is_available() {
-        global $DB, $USER;
-        $courseid = $this->make_course();
+        // Create course.
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course();
+
+        // Create activity with no restrictions and one with date restriction.
+        $page1 = $generator->get_plugin_generator('mod_page')->create_instance(
+                array('course' => $course));
+        $time = time() + 100;
+        $avail = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":' . $time . '}]}';
+        $page2 = $generator->get_plugin_generator('mod_page')->create_instance(
+                array('course' => $course, 'availability' => $avail));
 
         // No conditions.
-        $cmid = $this->make_course_module($courseid);
-        $ci = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
+        $ci = new condition_info((object)array('id' => $page1->cmid),
+                CONDITION_MISSING_EVERYTHING);
+        $this->assertDebuggingCalled();
         $this->assertTrue($ci->is_available($text, false, 0));
+        $this->assertDebuggingCalled();
         $this->assertEquals('', $text);
 
-        // Time (from).
-        $time = time()+100;
-        $cmid = $this->make_course_module($courseid, array('availablefrom'=>$time));
-        $ci = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
-        $this->assertFalse($ci->is_available($text));
-        $this->assertRegExp('/'.preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))).'/', $text);
-
-        $time = time()-100;
-        $cmid = $this->make_course_module($courseid, array('availablefrom'=>$time));
-        $ci = new condition_info((object)array('id'=>$cmid),
-            CONDITION_MISSING_EVERYTHING);
-        $this->assertTrue($ci->is_available($text));
-        $this->assertEquals('', $text);
-        $this->assertRegExp('/'.preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))).'/', $ci->get_full_information());
-
-        // Time (until).
-        $cmid = $this->make_course_module($courseid, array('availableuntil'=>time()-100));
-        $ci = new condition_info((object)array('id'=>$cmid),
+        // Date condition.
+        $ci = new condition_info((object)array('id' => $page2->cmid),
             CONDITION_MISSING_EVERYTHING);
+        $this->assertDebuggingCalled();
         $this->assertFalse($ci->is_available($text));
-        $this->assertEquals('', $text);
-
-        // Completion.
-        $oldid = $cmid;
-        $cmid = $this->make_course_module($courseid);
-        $this->make_section($courseid, array($oldid, $cmid), 1);
-        $oldcm = $DB->get_record('course_modules', array('id'=>$oldid));
-        $oldcm->completion = COMPLETION_TRACKING_MANUAL;
-        $DB->update_record('course_modules', $oldcm);
-
-        // Need to reset modinfo after changing the options.
-        rebuild_course_cache($courseid);
-
-        $ci = new condition_info((object)array('id'=>$cmid), CONDITION_MISSING_EVERYTHING);
-        $ci->add_completion_condition($oldid, COMPLETION_COMPLETE);
-        $this->wipe_condition_cache();
-
-        $this->assertFalse($ci->is_available($text, false));
-        $this->assertEquals(get_string('requires_completion_1', 'condition', 'xxx'), $text);
-        completion_info::wipe_session_cache();
-        $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
-        $completion->update_state($oldcm, COMPLETION_COMPLETE);
-        completion_info::wipe_session_cache();
-        $this->wipe_condition_cache();
-
-        $this->assertTrue($ci->is_available($text));
-        $this->assertFalse($ci->is_available($text, false, $USER->id+1));
-        completion_info::wipe_session_cache();
-        $this->wipe_condition_cache();
-        $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
-        $completion->update_state($oldcm, COMPLETION_INCOMPLETE);
-        $this->assertFalse($ci->is_available($text));
+        $this->assertDebuggingCalled();
+        $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
+        $this->assertContains($expectedtime, $text);
 
-        $ci->wipe_conditions();
-        $ci->add_completion_condition($oldid, COMPLETION_INCOMPLETE);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-        $this->assertTrue($ci->is_available($text, false, $USER->id+1));
-
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text, true));
-
-        // Grade.
-        $ci->wipe_conditions();
-        // Add a fake grade item.
-        $gradeitemid = $DB->insert_record('grade_items', (object)array(
-            'courseid'=>$courseid, 'itemname'=>'frog'));
-        // Add a condition on a value existing...
-        $ci->add_grade_condition($gradeitemid, null, null, true);
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_any', 'condition', 'frog'), $text);
-
-        // Fake it existing.
-        $DB->insert_record('grade_grades', (object)array(
-            'itemid'=>$gradeitemid, 'userid'=>$USER->id, 'finalgrade'=>3.78));
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text, true));
-
-        // Now require that user gets more than 3.78001.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
-        $this->wipe_condition_cache();
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
-
-        // ...just on 3.78...
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3.78, null, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // ...less than 3.78.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, null, 3.78, true);
-        $this->wipe_condition_cache();
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
-
-        // ...less than 3.78001.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // ...in a range that includes it.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3, 4, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // ...in a range that doesn't include it.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 4, 5, true);
-        $this->wipe_condition_cache();
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
+        // Full information display.
+        $text = $ci->get_full_information();
+        $this->assertDebuggingCalled();
+        $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
+        $this->assertContains($expectedtime, $text);
     }
 
+    /**
+     * Tests the is_available function for sections.
+     */
     public function test_section_is_available() {
-        global $DB, $USER;
-        $courseid = $this->make_course();
-
-        // Enrol user (needed for groups).
-        $enrolplugin = enrol_get_plugin('manual');
-        $course = $DB->get_record('course', array('id' => $courseid));
-        $enrolplugin->add_instance($course);
-        $enrolinstances = enrol_get_instances($courseid, false);
-        foreach ($enrolinstances as $enrolinstance) {
-            if ($enrolinstance->enrol === 'manual') {
-                break;
-            }
-        }
-        $enrolplugin->enrol_user($enrolinstance, $USER->id);
-
-        // Module for conditions later.
-        $cmid = $this->make_course_module($courseid);
+        global $DB;
 
-        // No conditions.
-        $sectionid = $this->make_section($courseid, array($cmid), 1);
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $this->assertTrue($ci->is_available($text, false, 0));
-        $this->assertEquals('', $text);
+        // Create course.
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course(
+                array('numsections' => 2), array('createsections' => true));
 
-        // Time (from).
+        // Set one of the sections unavailable.
         $time = time() + 100;
-        $sectionid = $this->make_section($courseid, array(), 2, array('availablefrom' => $time));
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $this->assertFalse($ci->is_available($text));
-        $timetext = userdate($time, get_string('strftimedate', 'langconfig'));
-        $this->assertRegExp('~' . preg_quote($timetext) . '~', $text);
+        $avail = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":' . $time . '}]}';
+        $DB->set_field('course_sections', 'availability', $avail, array(
+                'course' => $course->id, 'section' => 2));
 
-        $time = time()-100;
-        $sectionid = $this->make_section($courseid, array(), 3, array('availablefrom' => $time));
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $this->assertTrue($ci->is_available($text));
-        $this->assertEquals('', $text);
-        $timetext = userdate($time, get_string('strftimedate', 'langconfig'));
-        $this->assertRegExp('~' . preg_quote($timetext) . '~', $ci->get_full_information());
+        $modinfo = get_fast_modinfo($course);
 
-        // Time (until).
-        $sectionid = $this->make_section($courseid, array(), 4, array('availableuntil' => time() - 100));
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-            CONDITION_MISSING_EVERYTHING);
-        $this->assertFalse($ci->is_available($text));
+        // No conditions.
+        $ci = new condition_info_section($modinfo->get_section_info(1));
+        $this->assertDebuggingCalled();
+        $this->assertTrue($ci->is_available($text, false, 0));
+        $this->assertDebuggingCalled();
         $this->assertEquals('', $text);
 
-        // Completion: first set up cm.
-        $sectionid = $this->make_section($courseid, array(), 5);
-        $cm = $DB->get_record('course_modules', array('id' => $cmid));
-        $cm->completion = COMPLETION_TRACKING_MANUAL;
-        $DB->update_record('course_modules', $cm);
-
-        // Completion: Reset modinfo after changing the options.
-        rebuild_course_cache($courseid);
-
-        // Completion: Add condition.
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $ci->add_completion_condition($cmid, COMPLETION_COMPLETE);
-        $this->wipe_condition_cache();
-
-        // Completion: Check.
-        $this->assertFalse($ci->is_available($text, false));
-        $this->assertEquals(get_string('requires_completion_1', 'condition', 'xxx'), $text);
-        completion_info::wipe_session_cache();
-        $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
-        $completion->update_state($cm, COMPLETION_COMPLETE);
-        completion_info::wipe_session_cache();
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-        $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
-
-        // Completion: Uncheck.
-        completion_info::wipe_session_cache();
-        $this->wipe_condition_cache();
-        $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
-        $completion->update_state($cm, COMPLETION_INCOMPLETE);
-        $this->assertFalse($ci->is_available($text));
-
-        // Completion: Incomplete condition.
-        $ci->wipe_conditions();
-        $ci->add_completion_condition($cmid, COMPLETION_INCOMPLETE);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-        $this->assertTrue($ci->is_available($text, false, $USER->id + 1));
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text, true));
-
-        // Grade: Add a fake grade item.
-        $gradeitemid = $DB->insert_record('grade_items', (object)array(
-            'courseid' => $courseid, 'itemname' => 'frog'));
-
-        // Grade: Add a condition on a value existing.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, null, null, true);
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_any', 'condition', 'frog'), $text);
-
-        // Grade: Fake it existing.
-        $DB->insert_record('grade_grades', (object)array(
-            'itemid' => $gradeitemid, 'userid' => $USER->id, 'finalgrade' => 3.78));
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text, true));
-
-        // Grade: Now require that user gets more than 3.78001.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
-        $this->wipe_condition_cache();
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
-
-        // Grade: ...just on 3.78...
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3.78, null, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // Grade: ...less than 3.78.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, null, 3.78, true);
-        $this->wipe_condition_cache();
+        // Date condition.
+        $ci = new condition_info_section($modinfo->get_section_info(2));
+        $this->assertDebuggingCalled();
         $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
-
-        // Grade: ...less than 3.78001.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // Grade: ...in a range that includes it.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 3, 4, true);
-        $this->wipe_condition_cache();
-        $this->assertTrue($ci->is_available($text));
-
-        // Grade: ...in a range that doesn't include it.
-        $ci->wipe_conditions();
-        $ci->add_grade_condition($gradeitemid, 4, 5, true);
-        $this->wipe_condition_cache();
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
-
-        // Grouping: Not member.
-        $groupingid = $this->make_grouping($courseid, 'Grouping');
-        $groupid = $this->make_group($courseid, 'Group', $groupingid);
-        $sectionid = $this->make_section($courseid, array(), 6, array('groupingid' => $groupingid));
-        $ci = new condition_info_section((object)array('id' => $sectionid),
-                CONDITION_MISSING_EVERYTHING);
-        $this->assertFalse($ci->is_available($text));
-        $this->assertEquals(trim(get_string('groupingnoaccess', 'condition')), $text);
-
-        // Grouping: Member.
-        $this->assertTrue(groups_add_member($groupid, $USER->id));
-
-        condition_info_section::init_global_cache();
-        $this->assertTrue($ci->is_available($text));
-        $this->assertEquals('', $text);
-        $this->assertTrue($ci->is_available($text, true));
-
-        // Grouping: Somebody else.
-        $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
-        $this->assertFalse($ci->is_available($text, true, $USER->id + 1));
-    }
-
-    /**
-     * Tests user fields to ensure that the list of provided fields includes only
-     * fields which the equivalent function can be used to obtain the value of.
-     */
-    public function test_condition_user_fields() {
-        global $CFG, $DB, $USER;
-
-        // Set up basic data.
-        $courseid = $this->make_course();
-        $cmid = $this->make_course_module($courseid);
-        $ci = new condition_info_testwrapper(
-                (object)array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
-
-        // Add a custom user profile field. Unfortunately there is no back-end
-        // API for adding profile fields without having an actual form and doing
-        // redirects and stuff! These are the default text field parameters.
-        require_once($CFG->dirroot . '/user/profile/lib.php');
-        $field = (object)array(
-                'shortname' => 'myfield', 'name' => 'My field', 'required' => 0,
-                'locked' => 0, 'forceunique' => 0, 'signup' => 0,
-                'visible' => PROFILE_VISIBLE_ALL,
-                'datatype' => 'text', 'description' => 'A field of mine',
-                'descriptionformat' => FORMAT_HTML, 'defaultdata' => '',
-                'defaultdataformat' => FORMAT_HTML, 'param1' => 30, 'param2' => 2048,
-                'param3' => 0, 'param4' => '', 'param5' => '');
-        $customfieldid = $DB->insert_record('user_info_field', $field);
-
-        // Get list of condition user fields.
-        $fields = condition_info::get_condition_user_fields();
-
-        // Check custom field is included.
-        $this->assertEquals('My field', $fields[$customfieldid]);
-
-        // For all other fields, check it actually works to get data from them.
-        foreach ($fields as $fieldid => $name) {
-            // Not checking the result, just that it's possible to get it
-            // without error.
-            $ci->inspect_get_cached_user_profile_field($USER->id, $fieldid);
-        }
-
-        // Change to not logged in user.
-        $this->setUser(null);
-
-        foreach ($fields as $fieldid => $name) {
-            // Should get false always when not logged in.
-            $this->assertEquals(false, $ci->inspect_get_cached_user_profile_field($USER->id, $fieldid));
-        }
-    }
-}
-
-
-/**
- * Test wrapper used only to make protected functions public so they can be
- * tested.
- */
-class condition_info_testwrapper extends condition_info {
-    public function inspect_get_cached_user_profile_field($userid, $fieldid) {
-        return parent::get_cached_user_profile_field($userid, $fieldid);
+        $this->assertDebuggingCalled();
+        $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
+        $this->assertContains($expectedtime, $text);
+
+        // Full information display.
+        $text = $ci->get_full_information();
+        $this->assertDebuggingCalled();
+        $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
+        $this->assertContains($expectedtime, $text);
     }
 }