MDL-32188 question engine: behaviour static methods -> new classes

It was always a bit of a hack to use static methods on the
qbehaviour_whatever classes to return metadata about the behaviour. It
is better design to have real qbehaviour_whatever_type classes to report
that metadata, particularly now that we are planning to add more such.

For example, inheritance works better with real classes. See, for
example, the improvements in
question_engine::get_behaviour_unused_display_options().

This change has been implemented in a backwards-compatbile way. Old
behaviours will continue to work. There will just be some developer debug
output to prompt people to upgrade their code properly.
This commit is contained in:
Tim Hunt 2012-08-09 19:42:57 +01:00
parent 56cc9b387e
commit f3460297a9
29 changed files with 682 additions and 105 deletions

View File

@ -55,7 +55,7 @@ echo $OUTPUT->heading(format_string($attemptobj->get_question_name($slot)));
// Process any data that was submitted.
if (data_submitted() && confirm_sesskey()) {
if (optional_param('submit', false, PARAM_BOOL) && question_behaviour::is_manual_grade_in_range($attemptobj->get_uniqueid(), $slot)) {
if (optional_param('submit', false, PARAM_BOOL) && question_engine::is_manual_grade_in_range($attemptobj->get_uniqueid(), $slot)) {
$transaction = $DB->start_delegated_transaction();
$attemptobj->process_submitted_actions(time());
$transaction->allow_commit();

View File

@ -461,7 +461,7 @@ class quiz_grading_report extends quiz_default_report {
foreach ($qubaids as $qubaid) {
foreach ($slots as $slot) {
if (!question_behaviour::is_manual_grade_in_range($qubaid, $slot)) {
if (!question_engine::is_manual_grade_in_range($qubaid, $slot)) {
return false;
}
}

View File

@ -0,0 +1,39 @@
<?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/>.
/**
* Question behaviour type for adaptive behaviour.
*
* @package qbehaviour_adaptive
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for adaptive behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_adaptive_type extends question_behaviour_type {
public function is_archetypal() {
return true;
}
}

View File

@ -38,8 +38,6 @@ require_once(dirname(__FILE__) . '/../adaptive/behaviour.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_adaptivenopenalty extends qbehaviour_adaptive {
const IS_ARCHETYPAL = true;
protected function adjusted_fraction($fraction, $prevtries) {
return $fraction;
}

View File

@ -0,0 +1,38 @@
<?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/>.
/**
* Question behaviour type for adaptive behaviour, without penalties.
*
* @package qbehaviour_adaptivenopenalty
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(dirname(__FILE__) . '/../adaptive/behaviourtype.php');
/**
* Question behaviour type information for adaptive behaviour, without penalties.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_adaptivenopenalty_type extends qbehaviour_adaptive_type {
}

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines the quetsion behaviour base class
* Defines the question behaviour base class
*
* @package moodlecore
* @subpackage questionbehaviours
@ -40,21 +40,10 @@ defined('MOODLE_INTERNAL') || die();
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class question_behaviour {
/**
* Certain behaviours are definitive of a way that questions can
* behave when attempted. For example deferredfeedback model, interactive
* model, etc. These are the options that should be listed in the
* user-interface. These models should define the class constant
* IS_ARCHETYPAL as true. Other models are more implementation details, for
* example the informationitem model, or a special subclass like
* interactive_adapted_for_my_qtype. These models should IS_ARCHETYPAL as
* false.
* @var boolean
*/
const IS_ARCHETYPAL = false;
/** @var question_attempt the question attempt we are managing. */
protected $qa;
/** @var question_definition shortcut to $qa->get_question(). */
protected $question;
@ -95,16 +84,6 @@ abstract class question_behaviour {
return substr(get_class($this), 11);
}
/**
* 'Override' this method if there are some display options that do not make
* sense 'during the attempt'.
* @return array of {@link question_display_options} field names, that are
* not relevant to this behaviour before a 'finish' action.
*/
public static function get_unused_display_options() {
return array();
}
/**
* Cause the question to be renderered. This gets the appropriate behaviour
* renderer using {@link get_renderer()}, and adjusts the display
@ -190,17 +169,6 @@ abstract class question_behaviour {
return 0;
}
/**
* Adjust a random guess score for a question using this model. You have to
* do this without knowing details of the specific question, or which usage
* it is in.
* @param number $fraction the random guess score from the question type.
* @return number the adjusted fraction.
*/
public static function adjust_random_guess_score($fraction) {
return $fraction;
}
/**
* Return an array of the behaviour variables that could be submitted
* as part of a question of this type, with their types, so they can be
@ -477,20 +445,6 @@ abstract class question_behaviour {
return question_attempt::KEEP;
}
/**
* Validate that the manual grade submitted for a particular question is in range.
* @param int $qubaid the question_usage id.
* @param int $slot the slot number within the usage.
* @return bool whether the submitted data is in range.
*/
public static function is_manual_grade_in_range($qubaid, $slot) {
$prefix = 'q' . $qubaid . ':' . $slot . '_';
$mark = question_utils::optional_param_mark($prefix . '-mark');
$maxmark = optional_param($prefix . '-maxmark', null, PARAM_FLOAT);
$minfraction = optional_param($prefix . ':minfraction', null, PARAM_FLOAT);
return is_null($mark) || ($mark >= $minfraction * $maxmark && $mark <= $maxmark);
}
/**
* @param $comment the comment text to format. If omitted,
* $this->qa->get_manual_comment() is used.

View File

@ -0,0 +1,121 @@
<?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/>.
/**
* Defines the question behaviour type base class
*
* @package core
* @subpackage questionbehaviours
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* This class represents the type of behaviour, rather than the instance of the
* behaviour which control a particular question attempt.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class question_behaviour_type {
/**
* Certain behaviours are definitive of a way that questions can behave when
* attempted. For example deferredfeedback model, interactive model, etc.
* These are the options that should be listed in the user-interface, and
* for these behaviours this method should return true. Other behaviours are
* more implementation details, for example the informationitem behaviours,
* or a special subclass like interactive_adapted_for_my_qtype. These
* behaviours should return false.
* @return bool whether this is an archetypal behaviour.
*/
public function is_archetypal() {
return false;
}
/**
* Override this method if there are some display options that do not make
* sense 'during the attempt'.
* @return array of {@link question_display_options} field names, that are
* not relevant to this behaviour before a 'finish' action.
*/
public function get_unused_display_options() {
return array();
}
/**
* Adjust a random guess score for a question using this model. You have to
* do this without knowing details of the specific question, or which usage
* it is in.
* @param number $fraction the random guess score from the question type.
* @return number the adjusted fraction.
*/
public function adjust_random_guess_score($fraction) {
return $fraction;
}
}
/**
* This class exists to allow behaviours that worked in Moodle 2.3 to continue
* to work. It implements the question_behaviour_type API for the other behaviour
* as much as possible in a backwards-compatible way.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_behaviour_type_fallback extends question_behaviour_type {
/** @var string the behaviour class name. */
protected $behaviourclass;
/**
* @param string $behaviourtype the type of behaviour we are providing a fallback for.
*/
public function __construct($behaviour) {
question_engine::load_behaviour_class($behaviour);
$this->behaviourclass = 'qbehaviour_' . $behaviour;
}
public function is_archetypal() {
return constant($this->behaviourclass . '::IS_ARCHETYPAL');
}
/**
* Override this method if there are some display options that do not make
* sense 'during the attempt'.
* @return array of {@link question_display_options} field names, that are
* not relevant to this behaviour before a 'finish' action.
*/
public function get_unused_display_options() {
return call_user_func(array($this->behaviourclass, 'get_unused_display_options'));
}
/**
* Adjust a random guess score for a question using this model. You have to
* do this without knowing details of the specific question, or which usage
* it is in.
* @param number $fraction the random guess score from the question type.
* @return number the adjusted fraction.
*/
public function adjust_random_guess_score($fraction) {
return call_user_func(array($this->behaviourclass, 'adjust_random_guess_score'),
$fraction);
}
}

View File

@ -45,11 +45,6 @@ require_once(dirname(__FILE__) . '/../deferredfeedback/behaviour.php');
class qbehaviour_deferredcbm extends qbehaviour_deferredfeedback {
const IS_ARCHETYPAL = true;
public static function get_unused_display_options() {
return array('correctness', 'marks', 'specificfeedback', 'generalfeedback',
'rightanswer');
}
public function get_min_fraction() {
return question_cbm::adjust_fraction(parent::get_min_fraction(), question_cbm::HIGH);
}
@ -122,8 +117,4 @@ class qbehaviour_deferredcbm extends qbehaviour_deferredfeedback {
}
return $summary;
}
public static function adjust_random_guess_score($fraction) {
return question_cbm::adjust_fraction($fraction, question_cbm::default_certainty());
}
}

View File

@ -0,0 +1,41 @@
<?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/>.
/**
* Question behaviour type for deferred feedback with CBM behaviour.
*
* @package qbehaviour_deferredcbm
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(dirname(__FILE__) . '/../deferredfeedback/behaviourtype.php');
/**
* Question behaviour type information for deferred feedback with CBM behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_deferredcbm_type extends qbehaviour_deferredfeedback_type {
public function adjust_random_guess_score($fraction) {
return question_cbm::adjust_fraction($fraction, question_cbm::default_certainty());
}
}

View File

@ -38,17 +38,10 @@ defined('MOODLE_INTERNAL') || die();
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_deferredfeedback extends question_behaviour_with_save {
const IS_ARCHETYPAL = true;
public function is_compatible_question(question_definition $question) {
return $question instanceof question_automatically_gradable;
}
public static function get_unused_display_options() {
return array('correctness', 'marks', 'specificfeedback', 'generalfeedback',
'rightanswer');
}
public function get_min_fraction() {
return $this->question->get_min_fraction();
}

View File

@ -0,0 +1,44 @@
<?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/>.
/**
* Question behaviour type for deferred feedback behaviour.
*
* @package qbehaviour_deferredfeedback
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for deferred feedback behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_deferredfeedback_type extends question_behaviour_type {
public function is_archetypal() {
return true;
}
public function get_unused_display_options() {
return array('correctness', 'marks', 'specificfeedback', 'generalfeedback',
'rightanswer');
}
}

View File

@ -43,8 +43,6 @@ require_once(dirname(__FILE__) . '/../immediatefeedback/behaviour.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_immediatecbm extends qbehaviour_immediatefeedback {
const IS_ARCHETYPAL = true;
public function get_min_fraction() {
return question_cbm::adjust_fraction(parent::get_min_fraction(), question_cbm::HIGH);
}
@ -148,8 +146,4 @@ class qbehaviour_immediatecbm extends qbehaviour_immediatefeedback {
}
return $summary;
}
public static function adjust_random_guess_score($fraction) {
return question_cbm::adjust_fraction($fraction, question_cbm::default_certainty());
}
}

View File

@ -0,0 +1,41 @@
<?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/>.
/**
* Question behaviour type for immediate feedback with CBM behaviour.
*
* @package qbehaviour_adaptive
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(dirname(__FILE__) . '/../immediatefeedback/behaviourtype.php');
/**
* Question behaviour type information for immediate feedback with CBM.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_immediatecbm_type extends qbehaviour_immediatefeedback_type {
public function adjust_random_guess_score($fraction) {
return question_cbm::adjust_fraction($fraction, question_cbm::default_certainty());
}
}

View File

@ -0,0 +1,39 @@
<?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/>.
/**
* Question behaviour type for immediate feedback behaviour.
*
* @package qbehaviour_immediatefeedback
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for immediate feedback behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_immediatefeedback_type extends question_behaviour_type {
public function is_archetypal() {
return true;
}
}

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This behaviour is for informaiton items.
* This behaviour is for information items.
*
* @package qbehaviour
* @subpackage informationitem

View File

@ -0,0 +1,36 @@
<?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/>.
/**
* Question behaviour type for information item behaviour.
*
* @package qbehaviour_informationitem
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for informationitem items.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_informationitem_type extends question_behaviour_type {
}

View File

@ -40,8 +40,6 @@ defined('MOODLE_INTERNAL') || die();
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_interactive extends question_behaviour_with_save {
const IS_ARCHETYPAL = true;
/**
* Special value used for {@link question_display_options::$readonly when
* we are showing the try again button to the student during an attempt.

View File

@ -0,0 +1,39 @@
<?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/>.
/**
* Question behaviour type for interactive behaviour.
*
* @package qbehaviour_interactive
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for interactive behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_interactive_type extends question_behaviour_type {
public function is_archetypal() {
return true;
}
}

View File

@ -62,7 +62,6 @@ require_once(dirname(__FILE__) . '/../interactive/behaviour.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_interactivecountback extends qbehaviour_interactive {
const IS_ARCHETYPAL = false;
public function is_compatible_question(question_definition $question) {
return $question instanceof question_automatically_gradable_with_countback;

View File

@ -0,0 +1,41 @@
<?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/>.
/**
* Question behaviour type for interactive behaviour with count-back scoring behaviour.
*
* @package qbehaviour_interactivecountback
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(dirname(__FILE__) . '/../interactive/behaviourtype.php');
/**
* Question behaviour type information for interactive behaviour with count-back scoring.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_interactivecountback_type extends qbehaviour_interactive_type {
public function is_archetypal() {
return false;
}
}

View File

@ -38,17 +38,11 @@ defined('MOODLE_INTERNAL') || die();
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_manualgraded extends question_behaviour_with_save {
const IS_ARCHETYPAL = true;
public function is_compatible_question(question_definition $question) {
return $question instanceof question_with_responses;
}
public static function get_unused_display_options() {
return array('correctness', 'marks', 'specificfeedback', 'generalfeedback',
'rightanswer');
}
public function adjust_display_options(question_display_options $options) {
parent::adjust_display_options($options);

View File

@ -0,0 +1,44 @@
<?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/>.
/**
* Question behaviour type for manually graded behaviour.
*
* @package qbehaviour_manualgraded
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Question behaviour type information for manually graded behaviour.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_manualgraded_type extends question_behaviour_type {
public function is_archetypal() {
return true;
}
public function get_unused_display_options() {
return array('correctness', 'marks', 'specificfeedback', 'generalfeedback',
'rightanswer');
}
}

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fake question behaviour that is used when the actual qim was not
* Fake question behaviour that is used when the actual behaviour was not
* available.
*
* @package qbehaviour

View File

@ -0,0 +1,38 @@
<?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/>.
/**
* Fake question behaviour type that is used when the actual behaviour is not
* available.
*
* @package qbehaviour_missing
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Fake question behaviour type information that is used when the actual
* behaviour is not available.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_missing_type extends question_behaviour_type {
}

View File

@ -4,23 +4,43 @@ This files describes API changes for question behaviour plugins.
1) Legacy required_question_definition_type no longer supported. (See 2.2 point 2) below.)
2) Behaviours now have to define an extra class
class qbehaviour_mybehaviour_type extends question_behaviour_type {
This class returns information about the type of behaviour, as opposed to
the qbehaviour_mybehaviour class which controls a particular
question_attempt. That is like the difference between the qtype_mytype and
the qtype_mytype_question classes.
Practically, what this means is that any of the methods that used to be
static methods of qbehaviour_mybehaviour class are now normal instance methods
of the qbehaviour_mybehaviour_type class. Specifically.
2.5 / qbehaviour_mybehaviour -> 2.6 / qbehaviour_mybehaviour_type
IS_ARCHETYPAL -> is_archetypal()
adjust_random_guess_score() -> adjust_random_guess_score()
get_unused_display_options() -> get_unused_display_options()
3) The static method is_manual_grade_in_range has move from the
question_behaviour class to the question_engine class.
=== 2.3 ===
1) This plugin type now supports cron in the standard way. If required, Create a
lib.php file containing
function qbehaviour_mypluginname_cron() {};
=== 2.2 ===
1) The old
public static function get_required_behaviours()
method is no more. Instead use the ->dependencies facility in version.php. E.g.
method is no more. Instead use the ->dependencies facility in version.php. E.g.
$plugin->dependencies = array(
'qbehaviour_immediatefeedback' => 2011102700,
'qbehaviour_deferredcbm' => 2011102700
);
2) The old required_question_definition_type method has been replaced by a new
is_compatible_question method. You should change your behaviour to override the
new method, not the old one. This change has been implemented in a
backwards-compatible way, so behaviours will not break.
is_compatible_question method. You should change your behaviour to override
the new method, not the old one. This change has been implemented in a
backwards-compatible way, so behaviours will not break.

View File

@ -37,6 +37,7 @@ require_once(dirname(__FILE__) . '/bank.php');
require_once(dirname(__FILE__) . '/../type/questiontypebase.php');
require_once(dirname(__FILE__) . '/../type/questionbase.php');
require_once(dirname(__FILE__) . '/../type/rendererbase.php');
require_once(dirname(__FILE__) . '/../behaviour/behaviourtypebase.php');
require_once(dirname(__FILE__) . '/../behaviour/behaviourbase.php');
require_once(dirname(__FILE__) . '/../behaviour/rendererbase.php');
require_once($CFG->libdir . '/questionlib.php');
@ -56,6 +57,9 @@ abstract class question_engine {
/** @var array behaviour name => 1. Records which behaviours have been loaded. */
private static $loadedbehaviours = array();
/** @var array behaviour name => question_behaviour_type for this behaviour. */
private static $behaviourtypes = array();
/**
* Create a new {@link question_usage_by_activity}. The usage is
* created in memory. If you want it to persist, you will need to call
@ -127,6 +131,20 @@ abstract class question_engine {
$dm->set_max_mark_in_attempts($qubaids, $slot, $newmaxmark);
}
/**
* Validate that the manual grade submitted for a particular question is in range.
* @param int $qubaid the question_usage id.
* @param int $slot the slot number within the usage.
* @return bool whether the submitted data is in range.
*/
public static function is_manual_grade_in_range($qubaid, $slot) {
$prefix = 'q' . $qubaid . ':' . $slot . '_';
$mark = question_utils::optional_param_mark($prefix . '-mark');
$maxmark = optional_param($prefix . '-maxmark', null, PARAM_FLOAT);
$minfraction = optional_param($prefix . ':minfraction', null, PARAM_FLOAT);
return is_null($mark) || ($mark >= $minfraction * $maxmark && $mark <= $maxmark);
}
/**
* @param array $questionids of question ids.
* @param qubaid_condition $qubaids ids of the usages to consider.
@ -150,12 +168,13 @@ abstract class question_engine {
* @return question_behaviour an instance of appropriate behaviour class.
*/
public static function make_archetypal_behaviour($preferredbehaviour, question_attempt $qa) {
self::load_behaviour_class($preferredbehaviour);
$class = 'qbehaviour_' . $preferredbehaviour;
if (!constant($class . '::IS_ARCHETYPAL')) {
if (!self::is_behaviour_archetypal($preferredbehaviour)) {
throw new coding_exception('The requested behaviour is not actually ' .
'an archetypal one.');
}
self::load_behaviour_class($preferredbehaviour);
$class = 'qbehaviour_' . $preferredbehaviour;
return new $class($qa, $preferredbehaviour);
}
@ -165,12 +184,7 @@ abstract class question_engine {
* not relevant to this behaviour before a 'finish' action.
*/
public static function get_behaviour_unused_display_options($behaviour) {
self::load_behaviour_class($behaviour);
$class = 'qbehaviour_' . $behaviour;
if (!method_exists($class, 'get_unused_display_options')) {
return question_behaviour::get_unused_display_options();
}
return call_user_func(array($class, 'get_unused_display_options'));
return self::get_behaviour_type($behaviour)->get_unused_display_options();
}
/**
@ -213,9 +227,67 @@ abstract class question_engine {
throw new coding_exception('Unknown question behaviour ' . $behaviour);
}
include_once($file);
$class = 'qbehaviour_' . $behaviour;
if (!class_exists($class)) {
throw new coding_exception('Question behaviour ' . $behaviour .
' does not define the required class ' . $class . '.');
}
self::$loadedbehaviours[$behaviour] = 1;
}
/**
* Create an behaviour for a particular type. If that type cannot be
* found, return an instance of qbehaviour_missing.
*
* Normally you should use {@link make_archetypal_behaviour()}, or
* call the constructor of a particular model class directly. This method
* is only intended for use by {@link question_attempt::load_from_records()}.
*
* @param string $behaviour the type of model to create.
* @param question_attempt $qa the question attempt the model will process.
* @param string $preferredbehaviour the preferred behaviour for the containing usage.
* @return question_behaviour_type an instance of appropriate behaviour class.
*/
public static function get_behaviour_type($behaviour) {
if (array_key_exists($behaviour, self::$behaviourtypes)) {
return self::$behaviourtypes[$behaviour];
}
self::load_behaviour_type_class($behaviour);
$class = 'qbehaviour_' . $behaviour . '_type';
if (class_exists($class)) {
self::$behaviourtypes[$behaviour] = new $class();
} else {
debugging('Question behaviour ' . $behaviour .
' does not define the required class ' . $class . '.', DEBUG_DEVELOPER);
self::$behaviourtypes[$behaviour] = new question_behaviour_type_fallback($behaviour);
}
return self::$behaviourtypes[$behaviour];
}
/**
* Load the behaviour type class for a particular behaviour. That is,
* include_once('/question/behaviour/' . $behaviour . '/behaviourtype.php').
* @param string $behaviour the behaviour name. For example 'interactive' or 'deferredfeedback'.
*/
protected static function load_behaviour_type_class($behaviour) {
global $CFG;
if (isset(self::$behaviourtypes[$behaviour])) {
return;
}
$file = $CFG->dirroot . '/question/behaviour/' . $behaviour . '/behaviourtype.php';
if (!is_readable($file)) {
debugging('Question behaviour ' . $behaviour .
' is missing the behaviourtype.php file.', DEBUG_DEVELOPER);
}
include_once($file);
}
/**
* Return an array where the keys are the internal names of the archetypal
* behaviours, and the values are a human-readable name. An
@ -241,9 +313,7 @@ abstract class question_engine {
* @return bool whether this is an archetypal behaviour.
*/
public static function is_behaviour_archetypal($behaviour) {
self::load_behaviour_class($behaviour);
$plugin = 'qbehaviour_' . $behaviour;
return constant($plugin . '::IS_ARCHETYPAL');
return self::get_behaviour_type($behaviour)->is_archetypal();
}
/**

View File

@ -0,0 +1,7 @@
This files describes API changes for the core question system.
=== 2.4 ===
1) The method question_behaviour::is_manual_grade_in_range and move and become
question_engine::is_manual_grade_in_range.

View File

@ -43,8 +43,7 @@ class qtype_essay_question extends question_with_responses {
public $responsetemplateformat;
public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
question_engine::load_behaviour_class('manualgraded');
return new qbehaviour_manualgraded($qa, $preferredbehaviour);
return question_engine::make_behaviour('manualgraded', $qa, $preferredbehaviour);
}
/**

View File

@ -390,8 +390,7 @@ class question_information_item extends question_definition {
}
public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
question_engine::load_behaviour_class('informationitem');
return new qbehaviour_informationitem($qa, $preferredbehaviour);
return question_engine::make_behaviour('informationitem', $qa, $preferredbehaviour);
}
public function get_expected_data() {