dirroot.'/mod/choice/lib.php');
/**
* The Sloodle choice module class.
* @package sloodle
*/
class SloodleModuleChoice extends SloodleModule
{
// DATA //
/**
* Internal for Moodle only - course module instance.
* Corresponds to one record from the Moodle 'course_modules' table.
* @var object
* @access private
*/
var $cm = null;
/**
* Internal only - Moodle choice module instance database object.
* Corresponds to one record from the Moodle 'choice' table.
* @var object
* @access private
*/
var $moodle_choice_instance = null;
/**
* The number of (non-admin) users on the course who have not yet answered this choice.
* @var int
* @access private
*/
var $numunanswered = 0;
/**
* The options available for this choice, as an associative array of IDs to {@link SloodleChoiceOption} objects.
* @var array
* @access public
*/
var $options = array();
// FUNCTIONS //
/**
* Constructor
*/
function SloodleModuleChoice(&$_session)
{
$constructor = get_parent_class($this);
parent::$constructor($_session);
}
/**
* Loads data from the database.
* Note: even if the function fails, it may still have overwritten some or all existing data in the object.
* @param mixed $id The site-wide unique identifier for all modules. Type depends on VLE. On Moodle, it is an integer course module identifier ('id' field of 'course_modules' table)
* @return bool True if successful, or false otherwise
*/
function load($id)
{
// Make sure the ID is valid
$id = (int)$id;
if ($id <= 0) return false;
// Fetch the course module data
if (!($this->cm = get_coursemodule_from_id('choice', $id))) {
sloodle_debug("Failed to load course module instance #$id.
");
return false;
}
// Make sure the module is visible
if ($this->cm->visible == 0) {
sloodle_debug("Error: course module instance #$id not visible.
");
return false;
}
// Load from the primary table: choice instance
if (!($this->moodle_choice_instance = sloodle_get_record('choice', 'id', $this->cm->instance))) {
sloodle_debug("Failed to load choice with instance ID #{$cm->instance}.
");
return false;
}
// Fetch options
$this->options = array();
if ($options = sloodle_get_records('choice_options', 'choiceid', $this->moodle_choice_instance->id)) {
// Get response data (this uses the standard choice function, in "moodle/mod/choice/lib.php")
$allresponses = choice_get_response_data($this->moodle_choice_instance, $this->cm, 0);
foreach ($options as $opt) {
// Create our option object and add our data
$this->options[$opt->id] = new SloodleChoiceOption();
$this->options[$opt->id]->id = $opt->id;
$this->options[$opt->id]->text = $opt->text;
$this->options[$opt->id]->maxselections = $opt->maxanswers;
$this->options[$opt->id]->timemodified = (int)$opt->timemodified;
// Count the number of selections made
$numsels = 0;
if (isset($allresponses[$opt->id])) $numsels = count($allresponses[$opt->id]);
$this->options[$opt->id]->numselections = $numsels;
}
}
//$users = get_course_users($this->cm->course); // Deprecated since 1.7. Hope this works instead:
$context = get_context_instance(CONTEXT_COURSE, $this->cm->course);
$users = get_users_by_capability($context, 'mod/sloodle:courseparticipate', 'u.id', '','','',array(), false);
// Determine how many people on the course have not yet answered
if (!is_array($users)) $users = array();
$num_users = count($users);
$numanswers = (int)sloodle_count_records('choice_answers', 'choiceid', $this->moodle_choice_instance->id);
$this->numunanswered = max(0, $num_users - $numanswers);
return true;
}
/**
* Selects an option in this choice on behalf of the specified user.
* Logs the user in to the VLE if necessary.
* If a general error occurs, FALSE will be returned.
* Otherwise, an integer {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_status_codes status code} will be returned.
* The following status codes are typical responses:
* * 10011 = added new choice selection
* * 10012 = updated existing choice selection
* * 10013 = user previously selected same option
* * -10011 = User already made a selection, and re-selection is not allowed
* * -10012 = max number of selections for this option already made
* * -10013 = choice is not yet open
* * -10014 = choice is already closed
*
* @param mixed $optionid The unique site-wide identifier of the option to be selected
* @param mixed $user A SloodleUser identifying the current user; if omitted, the current {@link SloodleSession} will be used.
* @return integer|false
*/
function select_option($optionid, $user = null)
{
// Fetch a user if necessary
if ($user === null) {
// Make sure we have a session user
if (!isset($this->_session->user)) return false;
$user = $this->_session->user;
}
// Make sure we have a user loaded and logged-in
if (!$user->is_user_loaded()) return false;
if (!$user->login()) return false;
// Make sure the user is permitted to select from this choice
if (!has_capability('mod/choice:choose', get_context_instance(CONTEXT_MODULE, $this->cm->id))) return -331;
// Make sure the choice is open
if ($this->is_early()) return -10013;
if ($this->is_late()) return -10014;
// Has the user already made a selection for this choice?
$update_selection = false;
$previous_selection = sloodle_get_record('choice_answers', 'choiceid', $this->moodle_choice_instance->id, 'userid', $user->get_user_id());
if ($previous_selection) {
// Was it a selection of the same option?
if ($previous_selection->optionid == $optionid) {
// Yes - that's fine. Nothing to do.
return 10013;
}
// No - are re-selections allowed?
if (!$this->allow_update()) {
// No - stop here
return -10011;
}
$update_selection = true;
}
// Fetch the option record
$option = sloodle_get_record('choice_options', 'id', $optionid, 'choiceid', $this->moodle_choice_instance->id);
if (!$option) return false;
// Make sure the maximum selections for the given option have not yet been made
if (!empty($this->moodle_choice_instance->limitanswers)) {
$numselections = sloodle_count_records('choice_answers', 'optionid', $optionid);
if (!$numselections) return false;
if ($numselections >= $option->maxanswers) return -10012;
}
// If necessary, delete the existing selection
if ($update_selection) sloodle_delete_records('choice_answers', 'choiceid', $this->moodle_choice_instance->id, 'userid', $user->get_user_id());
// Select the new option
$selection = new stdClass();
$selection->choiceid = $this->moodle_choice_instance->id;
$selection->userid = $user->get_user_id();
$selection->optionid = $optionid;
$selection->timemodified = time();
if (!sloodle_insert_record('choice_answers', $selection)) return false;
// Success!
if ($update_selection) return 10012;
return 10011;
}
// ACCESSORS //
/**
* Gets the name of this module instance.
* @return string The name of this controller
*/
function get_name()
{
return $this->moodle_choice_instance->name;
}
/**
* Gets the intro description of this module instance, if available.
* @return string The intro description of this controller
*/
function get_intro()
{
// Seems to have changed somewhere before Moodle 2.3
return isset($this->moodle_choice_instance->text) ? $this->moodle_choice_instance->text : $this->moodle_choice_instance->intro;
}
/**
* Gets the identifier of the course this controller belongs to.
* @return mixed Course identifier. Type depends on VLE. (In Moodle, it will be an integer).
*/
function get_course_id()
{
return (int)$this->moodle_choice_instance->course;
}
/**
* Gets the time at which this instance was created, or 0 if unknown.
* @return int Timestamp
*/
function get_creation_time()
{
return 0;
}
/**
* Gets the time at which this instance was last modified, or 0 if unknown.
* @return int Timestamp
*/
function get_modification_time()
{
return (int)$this->moodle_choice_instance->timemodified;
}
/**
* Gets the short type name of this instance.
* @return string
*/
function get_type()
{
return 'choice';
}
/**
* Gets the full type name of this instance, according to the current language pack, if available.
* Note: should be overridden by sub-classes.
* @return string Full type name if possible, or the short name otherwise.
*/
function get_type_full()
{
return get_string('modulename', 'choice');
}
/**
* Gets the time at which this choice opens.
* @return int Timestamp. 0 if choice has no opening time.
*/
function get_opening_time()
{
return (int)$this->moodle_choice_instance->timeopen;
}
/**
* Gets the time at which this choice closes.
* @return int Timestamp. 0 if choice has no closing time.
*/
function get_closing_time()
{
return (int)$this->moodle_choice_instance->timeclose;
}
/**
* Determines if the choice is currently open.
* @param int $timestamp The time to test. Uses the current time if none is given.
* @return bool
*/
function is_open($timestamp = null)
{
// Use the current time if necessary
if ($timestamp === null) $timestamp = time();
// Check against the opening and closing times
$open = $this->get_opening_time();
$close = $this->get_closing_time();
if ($open > 0 && $open > $timestamp) return false;
if ($close > 0 && $close < $timestamp) return false;
return true;
}
/**
* Determines if the choice has not opened yet.
* @param int $timestamp The time to test. Uses the current time if none is given.
* @return bool
*/
function is_early($timestamp = null)
{
// Use the current time if necessary
if ($timestamp === null) $timestamp = time();
// Check against the opening time
$open = $this->get_opening_time();
if ($open == 0) return false; // No opening time - can never be early
return ($open > $timestamp);
}
/**
* Determines if the choice has already closed.
* @param int $timestamp The time to test. Uses the current time if none is given.
* @return bool
*/
function is_late($timestamp = null)
{
// Use the current time if necessary
if ($timestamp === null) $timestamp = time();
// Check against the closing time
$close = $this->get_closing_time();
if ($close == 0) return false; // No opening time - can never be early
return ($close < $timestamp);
}
/**
* Checks if users are allowed to re-select their answer in this choice.
* @return bool
*/
function allow_update()
{
return !empty($this->moodle_choice_instance->allowupdate);
}
/**
* Checks if results are to be shown.
* (Some choices only allow results after the choice is closed).
* @return bool
*/
function can_show_results()
{
if ($this->moodle_choice_instance->showresults == CHOICE_SHOWRESULTS_ALWAYS) return true;
if ($this->moodle_choice_instance->showresults == CHOICE_SHOWRESULTS_AFTER_CLOSE && $this->is_late()) return true;
return false;
}
/**
* Gets the number of people who have not yet answered the choice.
* Counts all users on the course, including students and teachers.
* @return int
*/
function get_num_unanswered()
{
return $this->numunanswered;
}
}
/**
* Class to represent a single available option for a choice.
* @package sloodle
*/
class SloodleChoiceOption
{
/**
* The ID of the option (should be unique across the site).
* @var mixed
* @access public
*/
var $id = 0;
/**
* The text of this option.
* @var string
* @access public
*/
var $text = '';
/**
* Number of selections so far of this option.
* @var int
* @access public
*/
var $numselections = 0;
/**
* Maximum allowed number of selections for this option.
* Note: will be -1 if there is no limit.
* @var int
* @access public
*/
var $maxselections = -1;
/**
* Timestamp of when this option was last modified.
* $var int
* @access public
*/
var $timemodified = 0;
}
?>