Activity module 是 moodle 里最复杂的 module 类型。 Assignment, Quiz 等 module 都属于 activity module 。
Activity module can support for gradebook connectivity, course groups, course reset, and backup and restore.
一个典型的 Activity 都应该包含下列文件
mod_form.php - a form to set up or update an instance of this module version.php - defines some meta-info icon.gif - a 16x16 icon for the module db/install.xml - defines the structure of db tables for all database types. Is used during module installation db/upgrade.php - defines changes in the structure of db tables. Is used during module upgrade db/access.php - defines module capabilities index.php - a page to list all instances in a course view.php - a page to view a particular instance lib.php - any/all functions defined by the module should be in here. If the module name is called widget , then the required functions include:· widget_install() - will be called during the installation of the module
· widget_add_instance() - code to add a new instance of widget
· widget_update_instance() - code to update an existing instance
· widget_delete_instance() - code to delete an instance
· widget_user_outline() - given an instance, return a summary of a user's contribution
· widget_user_complete() - given an instance, print details of a user's contribution
· widget_get_view_actions() / widget_get_post_actions() - Used by the participation report (course/report/participation/index.php) to classify actions in the logs table.
· Other functions available but not required are:
o widget_delete_course() - code to clean up anything that would be leftover after all instances are deleted
o widget_process_options() - code to pre-process the form data from module settings
o widget_reset_course_form() and widget_delete_userdata() - used to implement Reset course feature.
· To avoid possible conflict, any module functions should be named starting with widget_ and any constants you define should start with WIDGET_
backuplib.php and restorelib.php (optional) settings.php or settingstree.php - (optional) a definition of an admin settings page for this module. mod/assignment/settings.php is a good simple example. mod/quiz/settingstree.php is a more complex example. defaults.php - lets you easily define default values for your configuration variables. It is included by upgrade_activity_modules in lib/adminlib.php. It should define an array $defaults. These values are then loaded into the config table. Alternatively, if you set $defaults['_use_config_plugins'] to true, the values are instead loaded into the config_plugins table, which is better practice. See mod/quiz/defaults.php for an example. (This apparently only works with moodle 2.x branch.) lang/en_utf8/widget.php - (optional) Lastly, each module will have some language files that contain strings for that module.
Moodle 提供了一个 activity template named NEWMODULE , you can download it at http://moodle.org/mod/data/view.php?d=13&rid=715&filter=1 . 当你开发 activity 时应该 based on NEWMODULE 。需要注意的是, NEWMODULE 还是缺少了非常重要的功能没有涉及: backup and restore 。少了这 2 个功能后果会很严重,很多 moodle system 不会安装缺少这 2 个 function 的 activity module 。
下面以开发一个最为简单的 “Foo” activity 为例。 It includes following features
l gradebook connectivity
l course groups
l course reset
l backup and restore
Step 1 use NEWMODULE as template
1. 下载最新的 NEWMODULE
2. rename “newmodule” folder to our module name “foo”
3. search 目录下所有文件的内容,用 ”foo” 替代 ”newmodule”
4. rename lang/en_utf8/ newmodule.php to foo.php
5. copy the whole “foo” folder to <moodle home>/mod folder
Step 2 修改 mod_form.php (important)
mod_form.php 提供了当 teacher create a new module instance 时出现的 form interface , teacher 可以在该 form 输入对该 module instance 的 setting 。
mod_form.php 要定义一个 mod_<MODULE NAME>_mod_form class ,该 class 需要 extend moodleform_mod class .
require_once ($CFG->dirroot.'/course/moodleform_mod.php');
class mod_foo_mod_form extends moodleform_mod {
在 mod_foo_mod_form class 里,需要定义“ definition ” function ,并在该 function 里创建 form instance, and then add elements (activity instance name, instruction, date selector and grade option ) to the form instance 。 需要注意的是: added element name 必须和对应的 field name in database 相 match !!
function definition () {
global $COURSE, $CFG;
// Create form instance
$mform =& $this->_form;
// creates the form header
$mform->addElement('header', 'general', get_string('general', 'form'));
// create text input
$mform->addElement('text', 'name', get_string('fooname', 'foo'), array('size'=>'64'));
// input element type is controlled by the value of the setType element
$mform->setType('name', PARAM_TEXT);
// UI rules are defined by setting addRule
$mform->addRule('name', null, 'required', null, 'client');
// set instruction ( html editor input )
$mform->addElement('htmleditor', 'instructions', get_string('instructions', 'foo'));
$mform->setType('instructions', PARAM_RAW);
$mform->addRule('instructions', get_string('required'), 'required', null, 'client');
// create html editor help button
$mform->setHelpButton('instructions', array('questions', 'richtext'), false, 'editorhelpbutton');
//create date available ( date selector )
$mform->addElement('date_time_selector', 'timeavailable', get_string('timeavailable', 'foo'), array('optional'=>true));
$mform->setDefault('timeavailable', 0);
$mform->addElement('date_time_selector', 'timedue', get_string('timedue', 'foo'), array('optional'=>true));
$mform->setDefault('timedue', 0);
// set grade ( scale type input )
$mform->addElement('modgrade', 'scale', get_string('grade'), false);
$mform->disabledIf('scale', 'assessed', 'eq', 0);
// 调用 standard_coursemodule_elements 方法 为 common module 进行设置。
// 比如是否 support group 等
// 该方法同时也会 controls the display of multiple form elements.
$features = array('groups'=>true, 'groupings'=>true,
'groupmembersonly'=>true,'outcomes'=>false, 'gradecat'=>false, 'idnumber'=>false);
$this->standard_coursemodule_elements($features);
//add form buttons (cancel and submit)
$this->add_action_buttons();
}
Step 3 修改 version.php
version.php 用于 manage database upgrades and enforce required versions of Moodle. upgrade.php 会根据 version.php 的版本号来决定是否需要升级 (例如 upgrade related table in db )。该文件里定义了
l 该 module 的 current verison
l Moodle 的 require version
l 以及 cron
$module->version = 2009060103;
$module->requires = 2007101509;
$module->cron = 0;
Step 4 修改 icon.gif
Step 5 修改 install.xml
install.xml 定义了 the database structure for the module 。你可以基于 newmodule tempalte 的 install.xml 来通过 moodle XMLDB editor tool or 自己写代码来定义该 module 的 database structure 。
每个 activity module 必须至少有一个 db table ,而且该 table name 必须和 module name 相同。例如 foo activity 的 table name is foo 。该 table 最起码要包含下列 fields : id , name , intro , and modifiedtime
Foo activity 我们在 foo table 里多定义了一些 fields : course , timeavailable , timedue , and scale 。
另外, foo activity 还多定义了一个 table “ foo_responses ” ,该 table 包含了下列 fields : id , fooid , userid , response , and timemodified 。 该 table 用于 store one record for each user response in each foo activity instance 。
另外,在 install.xml 里,还定义了 database statements that are used to store user log data for a user's interaction with the module 。 newmodule template by default 对这部分是在 log_display table 定义了 view, add, and update action for each module 。你也可以添加更多的 action type for logging 。 Activity module 只是使用 default 的 codes
<STATEMENTS>
<STATEMENT NAME=" insert log_display " TYPE=" insert " TABLE=" log_display " COMMENT="Initial insert of records on table log_display">
<SENTENCES>
<SENTENCE TEXT="(module, action, mtable, field) VALUES ( 'foo', 'view', 'foo', 'name') " />
<SENTENCE TEXT="(module, action, mtable, field) VALUES ('foo', 'add' , 'foo', 'name')" />
<SENTENCE TEXT="(module, action, mtable, field) VALUES ('foo', 'update' , 'foo', 'name')" />
??其实上面这段在 table log_display 里添加 3 个 records 有什么用?
对于 install.xml ,如果该 activity module 已经开始使用,而你又有对 install.xml 进行修改,那么就要同时修改 version.php 。如果你是对 install.xml 的 database structure 进行修改,那么还要配合 upgrade.php 来进行 。
Step 6 修改 db/access.php
access.php controls which capabilities can be assigned for user access. Foo activity 定义了 2 个 capabilities :
l mod/foo:submit course student, teacher and admin are allowed
l mod/foo:viewall student role is not allowed
<?php
//Define access capbilities
$mod_foo_capabilities = array(
'mod/foo:submit ' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'legacy' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'admin' => CAP_ALLOW
)
),
'mod/foo:viewall ' => array(
'captype' => 'view',
'contextlevel' => CONTEXT_MODULE,
'legacy' => array(
'student' => CAP_PREVENT,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'admin' => CAP_ALLOW
)
)
);
?>
Step 7 修改 index.php (important)
index.php file 会 lists all of the instances of activity that are present in the course 以及当前 logined user 对所有 activity 的 response 。
//include moodle config file and foo activity lib.php
require_once (dirname (dirname (dirname (__FILE__))). '/config.php' );
require_once (dirname (__FILE__). '/lib.php' );
//get course id from request param
$id = required_param( 'id' , PARAM_INT); // course
// 如果 global var $course 与根据 id 从 db 获取的 course 不匹配,则 error
if (! $course = get_record( 'course' , 'id' , $id )) {
error( 'Course ID is incorrect' );
}
require_course_login( $course );
add_to_log( $course ->id, 'foo' , 'viewall' , "index.php?id= $course ->id " , '' );
$strfoos = get_string( 'modulenameplural' , 'foo' );
$strfoo = get_string( 'modulename' , 'foo' );
/// Print the header with navigation links
$navlinks = array ();
$navlinks[]=array('name' =>$strfoos, 'link' => '', 'type' => 'activity');
$navigation = build_navigation($navlinks);
print_header_simple($strfoos, '', $navigation, '', '', true, '', navmenu($course));
// get all “foo” activity instance in the course
if (! $foos = get_all_instances_in_course('foo', $course) ) {
// 如果 no instance, then call function notice to print msg and exit
notice (get_string( 'thereareno' , 'moodle' , $strfoos ), "../../course/view.php?id= $course ->id " ); //changed
die ;
}
// 获取当前 user 在该 course 的所有 foo activity instances 的 response
// 返回一个以 foo instance id 为 key , response record 为 value 的 array “responses”
$sql = "SELECT foo_a.*
FROM { $CFG ->prefix} foo foo_b,
{ $CFG ->prefix} foo_responses foo_a
WHERE foo_a.fooid = foo_b.id AND
foo_b.course = $course ->id AND foo_a.userid = $USER ->id " ;
$responses = array () ;
if (isloggedin() and !isguestuser()
and $allresponses = get_records_sql ( $sql )) {
foreach ( $allresponses as $ra ) {
$responses[$ra->fooid] = $ra;
}
unset ( $allresponses );
}
$timenow = time();
$strname = get_string( 'name' );
$strweek = get_string( 'week' );
$strtopic = get_string( 'topic' );
$userquery = get_string( 'userquery' , 'foo' );
$yes = get_string( 'yes' , 'foo' );
$no = get_string( 'no' , 'foo' );
//set table format according to course format
if ( $course->format == 'weeks' ) {
$table ->head = array ( $strweek , $strname , $userquery );
$table ->align = array ( 'center' , 'left' );
} else if ($course->format == 'topics' ) {
$table ->head = array ( $strtopic , $strname , $userquery );
$table ->align = array ( 'center' , 'left' , 'left' , 'left' );
} else {
$table ->head = array ( $strname , $userquery );
$table ->align = array ( 'left' , 'left' , 'left' );
}
// loop all foo instances in the course and print each foo info with response
foreach ( $foos as $foo ) {
if (! empty ( $responses [ $foo ->id])) {
$response = $responses [ $foo ->id];
} else {
$response = "" ;
}
if (! empty ( $response ->response)) {
if ( $response ->response == "1" ) {
$fa = $yes ;
}
else {
$fa = $no ;
} $response ->response;
} else {
$fa = $no ;
}
// Courses are divided into sections, typically weeks or topics, depending on the course
//format selected. Following code deals with section display.
// $foo 居然有一个 element “section” 包含了 session info
$printsection = "" ;
if ( $foo->section !== $currentsection ) {
if ( $foo ->section) {
$printsection = $foo ->section;
}
if ( $currentsection !== "" ) {
$table ->data[] = 'hr' ;
}
$currentsection = $foo ->section;
}
//Calculate the href
if (! $foo->visible ) { //check if the instance is hidden or visible
//Show dimmed if the mod is hidden
$tt_href = "<a class=/"dimmed/" href=/"view.php?id= $foo ->coursemodule /">" .format_string( $foo ->name, true ). "</a>" ;
} else {
//Show normal if the mod is visible
$tt_href = "<a href=/"view.php?id= $foo ->coursemodule /">" .format_string( $foo ->name, true ). "</a>" ;
}
if ( $course ->format == "weeks" || $course ->format == "topics" ) {
$table ->data[] = array ( $printsection , $tt_href , $fa );
} else {
$table ->data[] = array ( $tt_href , $fa );
}
}
print_heading($strfoos) ;
print_table ($table);
/// Finish the page
print_footer($course);
Step 8 修改 view.php (important)
view.php 是当 user (teacher or student) click 创建好的 activity instance 的 link 后出现的 interface 。
Foo activity 的 view.php 会
l 显示一条问题
l 如果 user 答过这条问题,会显示他的 response
l 处理当 user 在 view.php click cancel button
l 处理当 user 在 view.php click submit button
下面会讲解 view.php 里的一些重要代码
// submit_form.php 定义了一个 form class which extends moodleform,
//when user access foo activity instance, provide a form to user to submit
// moodleform 和之前所说的 moodleform_mod 用法相似。
require_once (dirname(__FILE__). '/submit_form.php' );
// 下面这部分代码是通过 course module id or module instance id 来获取对应的 course module object ($cm) , course object ($course) and foo instance object 。
//!! Course module object 是来自 table “mdl
// 注意: course module id 和 module instance id 是不同的,但又是相关的 。
// 例如,当 teacher create a foo activity instance 时,就会同时在 ”mdl_foo” table 和 ”mdl_course_modules” table 各 insert a record ,其中 ”mdl_foo” table 的 ”id” field 就是 module instance id ,而 ”mdl_course_modules” table 的 ”id” field 是该 instance 的 course module id ,而而 ”mdl_course_modules” table 的 ”instance” field 则是和 ”mdl_foo” table 的 ”id” field 匹配。你可以说 ”mdl_foo” table 和 ”mdl_course_modules” table 里的 record 是一对一关系。
// Course module object 是来自 table “ mdl_course_modules” record ,它包含有下列 fields: id (course module id), course (course id), module ( 对应 table mdl_modules 的 id), instance ( 对应 table mdl_foo 的 id), section ( 所在 course 里的 section id)
// 如果你想通过 instance id 来获取 course module record, 可以调用 get_coursemodule_from_instance function 。如果你想通过 course module id 来获取 course module record, 可以调用 get_coursemodule_from_id function
$id = optional_param ( 'id' , 0 , PARAM_INT); // course_module ID, or
$a = optional_param ( 'a' , 0 , PARAM_INT); // foo instance ID
if ( $id ) {
if (! $cm = get_coursemodule_from_id ( 'foo' , $id ))
error( 'Course Module ID was incorrect' );
if (! $course = get_record( 'course' , 'id' , $cm ->course))
error( 'Course is misconfigured' );
if (! $foo = get_record( 'foo' , 'id' , $cm ->instance))
error( 'Course module is incorrect' );
} else if ( $a ) {
if (! $foo = get_record( 'foo' , 'id' , $a ))
error( 'Course module is incorrect' );
if (! $course = get_record( 'course' , 'id' , $foo ->course))
error( 'Course is misconfigured' );
if (! $cm = get_coursemodule_from_instance ( 'foo' , $foo ->id, $course ->id))
error( 'Course Module ID was incorrect' );
}
//print navigation links
$navlinks = array ();
$navlinks [] = array ( 'name' => $strfoos , 'link' => "index.php?id= $course ->id " , 'type' => 'activity' );
$navlinks [] = array ( 'name' => format_string( $foo ->name), 'link' => '' , 'type' => 'activityinstance' );
$navigation = build_navigation ( $navlinks );
print_header_simple(format_string($foo->name), '', $navigation, '', '', true,update_module_button($cm->id, $course->id, $strfoo), navmenu($course, $cm));
// 获取该 module instance 的 context !!
$context = get_context_instance (CONTEXT_MODULE, $cm->id);
//check 当前 user 在该 context 里是否具有 submit permission ,如果没有 permission ,则不做任何事
if ( has_capability('mod/foo:submit', $context) ) {
// 然后下面是具有 submit permission 要进行的操作,分为 3 parts ,一是当 user 刚进入该 module instance 时的代码,二是当 user click cancel button ,三是当 user click submit button 。
// 注意,无论是刚进入该 instance ,还是 click cancel or submit button ,都由 view.php 处理。
$mform = new foo_submit_form( "view.php?id= $cm ->id " );
if ( $mform -> is_cancelled ()){ //when user click cancel button
} else if ( $fromform=$mform->get_data() ){ //when user click submit button
add_to_log( $course ->id, "foo" , "add response" , "view.php?id= $cm ->id " , $foo ->name, $cm ->id);
$response = new object();
$response ->response = $fromform ->response;
$response ->fooid = $foo ->id;
$response ->userid = $USER ->id;
$response ->timemodified = time();
// 如果 user 之前曾经 submit 过 , 则 update record
if ( $old_response = get_record( 'foo_responses' , 'fooid' , $response ->fooid, 'userid' , $USER ->id)) {
$response ->id = $old_response ->id;
if (! update_record( 'foo_responses' , $response )) {
echo get_string( 'errorupdateresponse' , 'foo' );
}
}
// 如果 user 未曾 submit 过 , 则 insert record
else {
if (! insert_record ( 'foo_responses' , $response )) echo get_string( 'errorinsertresponse' , 'foo' );
}
// Set grades ,详见该例子的 lib.php/foo_grade function
foo_grade ( $foo , $USER ->id, $response ->response);
} else {
}
//*** 显示 user 进入该 instance 时要显示的 form***
$data = new stdClass() ;
$data->cmid = $cm->id;
// get response if already exists to preload in form
if ( $old_response = get_record( 'foo_responses' , 'fooid' , $foo ->id, 'userid' , $USER ->id)) {
$data->response = $old_response->response;
}
$mform->set_data($data);
$mform->display() ;
//**************************
echo ( '<strong>' .get_string( 'submissions' , 'foo' ). '</strong><br>' );
//!! 显示 user 的 response!!
// 如果有 viewall permission ,则 show all participant responses
if ( has_capability('mod/foo:viewall', $context) && $participants = foo_get_participants ( $foo ->id)) {
foreach ( $participants as $id => $participant ) {
//print_object($id->id);
$user = get_record( 'user' , 'id' , $id );
echo ( '<br>' . $user ->firstname. " " . $user ->lastname. ': ' );
//call foo_user_complete function to look up their responses
foo_user_complete ( $user , $foo );
echo ( '</br>' );
}
}
// 若没有 viewall permission ,则显示 current user own response
else {
echo ( '<br>' );
foo_user_complete ( $USER , $foo );
// **** 下面部分是 support moodle group feature*****
// 如果 enable group ,那么就显示所在的 group 的其他 partipant responses
// see if groups are enabled for an activity
$groupmode = groups_get_activity_groupmode ( $cm );
if ( $groupmode ) {
groups_get_activity_group( $cm , true );
groups_print_activity_menu( $cm , 'view.php?id=' . $id );
}
/// Get the current group
if ( $groupmode > 0 ) {
$currentgroup = groups_get_activity_group ( $cm );
} else {
$currentgroup = 0 ;
}
/// Initialise the returned array, which is a matrix: $allresponses[responseid][userid] = responseobject
$allresponses = array ();
/// First get all the users who have access here
/// To start with we assume they are all "unanswered" then move them later
// get a list of all of the group participants and their user information
$allresponses [ 0 ] = get_users_by_capability ( $context , 'mod/foo:submit' , 'u.id, u.picture, u.firstname, u.lastname, u.idnumber' , 'u.firstname ASC' , '' , '' , $currentgroup , '' , false , true );
//get a complete list of all responses for this activity instance
//save this list in $rawresponses
$rawresponses = get_records('foo_responses', 'fooid', $foo->id);
if ( $rawresponses ) {
echo (get_string( 'your_groups_performance' , 'foo' ));
foreach ( $rawresponses as $response ) {
// This person is enrolled and in correct group
if ( isset($allresponses[0][$response->userid]) ) {
$userid = $response ->userid;
$user = get_record( 'user' , 'id' , $userid );
echo ( '<br>' . $user ->firstname. " " . $user ->lastname. ': ' );
foo_user_complete( $user , $foo );
}
}
}
echo ( '</br>' );
//**************************
}
Step 9 完成 lib.php
lib.php file stores all of the basic functions used by the other files in the module
大部分 moodle required 的 functions in lib.php 都包含在 newmodule template lib.php 里。许多在 newmodule 的 lib.php 定义的 function 都可以不加改变的用在我们 foo activity module 里。你也可以添加 function 到 lib.php 来实现代码共享,例如本例添加了一个 foo_grade function 。
注意:你可以通过把你添加的 functions 放入 locallib.php 而不是 lib.php 里,从而达到提供代码的执行性能。 这是因为 core Moodle functions 会 包含 module's lib.php file, 但不需要包含 locally added functions. The Moodle core programming guidelines state that it is only necessary to create a separate file if you make significant additions.
下面讲解一些 lib.php 里的 functions
l Function foo_add_instance
当一个 foo activity instance 被添加到 course 时,就会 call foo_add_instance function 。 The sample function provided by NEWMODULE is pretty complete, but it doesn't set the modification time. We add this line to set the modification time
$foo->timemodified = time();
l Function foo_delete_instance
当一个 foo activity instance 从 course 里被 delete 时,就会 call foo_delete_instance function 。 We just need to make one minor addition to the template. We need to delete any 'child' records stored in our foo_responses table that are related to this instance
if (delete_records("foo_responses", "fooid", "$foo->id")) {
$result = false;
}
l Function foo_user_outline
该 function 返回 a small object with summary information about what a user has done with a given particular instance of this module 。该 function 用于查看 user activity reports.
返回的变量 $result 包含下列 2 个 data
$return->time = the time they did it
$return->info = a short text description
l Function foo_user_complete
该 function 用于 prints the user's submission, if any, to the activity . This function is used by the core Moodle libraries, and also in activity Foo!'s view.php file. 该 例的该 function 用于输出参数 user 的 response ,获取的 response 和 function foo_user_outline 的方法一样。
l Function foo_get_participants
This function returns a list of all of the users that have participated in the activity
l Function reset_course_form_definition
Newmodule tempalte 并没有该 function 。 该 function 用于当 course 被 reset 时 。 This is called by Moodle core to build the course reset form displayed to the user. 该例中,会往 mform 里添加 2 个 elements
function foo_reset_course_form_definition(&$mform) {
$mform->addElement('header', 'fooheader', get_string('modulenameplural', 'foo'));
$mform->addElement('advcheckbox', 'reset_foo', get_string('removeresponses','foo'));
}
l Function foo_reset_course_form_defaults
This function is required to implement the course reset. It enables the display of our module in the course reset form
function foo_reset_course_form_defaults($course) {
return array('reset_foo'=>1);
}
l Function foo_reset_userdata
This function 是真正的对该 module 的 user data 进行 reset 的 function. It is called by Moodle core if a user selects the form value in the course reset 。该例中,它会 delete all the foo responses for course $data->courseid.
该函数的参数为 $data ,它包含 the data submitted from the reset course. 该函数返回的是 status array 。
function foo_reset_userdata ( $data ) {
global $CFG ;
$componentstr = get_string( 'modulenameplural' , 'foo' );
$status = array ();
// First, check to see if reset_foo was selected
if (! empty ( $data->reset_foo )) {
// 获取要 reset 的 course 所包含的 foo instance records and delete them
$foossql = "SELECT f.id
FROM { $CFG ->prefix} foo f
WHERE f.course= { $data ->courseid} " ;
delete_records_select ( 'foo_responses' , "fooid IN ( $foossql )" );
$status [] = array ( 'component' => $componentstr , 'item' =>get_string( 'removeresponses' , 'foo' ), 'error' => false );
}
/// updating dates - shift may be negative too
// reset the date values by using the shift_course_mod_dates function from the Moodle core
if ( $data ->timeshift) {
shift_course_mod_dates ( 'foo' , array ( 'timeopen' , 'timeclose' ), $data ->timeshift, $data ->courseid);
$status [] = array ( 'component' => $componentstr , 'item' =>get_string( 'datechanged' ), 'error' => false );
}
return $status ;
}
l Function foo_grade
该 function 用于 insert grade record to gradebook. It is called when user click submit button
该 function 演示了如何和 moodle gradebook 进行 interaction 。
该 foo activity 给分非常简化,如果答 Yes ,则给满分,如果答 No ,则给 0 分。
function foo_grade( $foo , $userid , $response ) {
global $CFG ;
if (!function_exists( 'grade_update' ))
//include grade lib file
require_once ( $CFG->libdir.'/gradelib.php' );
if ( $response == 0 )
$grade = 0 ;
else
$grade = $foo ->scale; // $foo->scale 即为满分
// assign a array with both elements userid and rawgrade
$grades = array('userid'=>$userid, 'rawgrade'=>$grade);
// assign some grading parameters
$params = array('itemname'=>$foo->name, 'idnumber'=>$foo->id);
// assign the grade type
if ( $foo ->scale == 0 ) {
$params['gradetype'] = GRADE_TYPE_NONE;
} else if ( $foo ->scale > 0 ) {
$ params [ 'gradetype' ] = GRADE_TYPE_VALUE;
$ params [ 'grademax' ] = $foo ->scale;
$ params [ 'grademin' ] = 0 ;
} else if ( $foo ->scale < 0 ) {
$ params [ 'gradetype' ] = GRADE_TYPE_SCALE;
$ params [ 'scaleid' ] = - $foo ->scale;
}
if ( $grades === 'reset' ) {
$params [ 'reset' ] = true ;
$grades = NULL;
}
// !最关键方法: insert/update grade record
return grade_update('mod/foo', $foo->course, 'mod', 'foo', $foo->id, 0, $grades, $params) ;
}
Step 10 upgrade.php
该 file 用于 module upgrade 。 It is only necessary if we have deployed our module to users and subsequently make updates that require the database to be changed.
最推荐的完成 upgrade.php 的方法是用 moodle XMLDB editor tool 。 It provides a GUI that you can use to update the database, including adding new tables. The editor will output both a complete new install.xml file and the PHP code needed for our upgrade.php file
下列代码是 a sample section of code generated from the XMLDB editor ,它讲解了当往 foo table 里添加一个 scale field 的代码
if ( $result && $oldversion < 2009060103 ) {
/// Define field scale to be added to foo
$table = new XMLDBTable('foo');
$field = new XMLDBField('scale');
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'timemodified');
/// Launch add field scale
$result = $result && add_field($table, $field);
关于 upgrade ,详见
http://docs.moodle.org/en/Development:Installing_and_upgrading_plugin_database_tables
Step 10 Creating backup and restore support
Moodle course backup system 使用 XML format 来保存 activity data 。 当 backup a course 时, moodle 会 call 所有 module 的 backuplib.php file 里的函数 。
如果某个 module 并没有提供 backuplib.php ,那么 backup course 就不会 backup 该 course 里该 module 的任何相关 data 。而且在 backup 时,不会提示该 module 的 data 没有 backup ,只会在 user restore course 时才发现!
restorelib.php 则包含了在 restore moodle course 时要调用的函数
注意: moodle 2.0 重写了 backup and restore 的方法,但会向后兼容。
下面是 foo activity backup xml example
<MOD>
<ID>80</ID>
<TYPE>foo</TYPE>
<INSTANCE>1</INSTANCE>
<ADDED>1250743636</ADDED>
<SCORE>0</SCORE>
<INDENT>0</INDENT>
<VISIBLE>1</VISIBLE>
<GROUPMODE>1</GROUPMODE>
<GROUPINGID>0</GROUPINGID>
<GROUPMEMBERSONLY>0</GROUPMEMBERSONLY>
<IDNUMBER>$@NULL@$</IDNUMBER>
<ROLES_OVERRIDES>
</ROLES_OVERRIDES>
<ROLES_ASSIGNMENTS>
</ROLES_ASSIGNMENTS>
</MOD>
下面是 response 保存到 backup xml file 的 example
<RESPONSE>
<ID>1</ID>
<USERID>2</USERID>
<RESPONSE>1</RESPONSE>
<TIMEMODIFIED>1250743885</TIMEMODIFIED>
</RESPONSE>
Foo activity 的 backuplib.php file 是 基于 moodle core 'choice' module ,代码 95% 是一样的。只是通过 search and replace “the module name” and database element 。
The foo_responses structure is very similar to the choice_answers table. 'choice' actually has three tables, so a few items were removed.
下面是 backuplib.php 的 functions (包括通用 functions and only for foo module functions )
Common backup functions
Common backup functions should be implemented for every activity module.
l foo_backup_mods() : The main entry point for the backup process. 它 会为每一个 activity instance in course 都调用一次方法 foo_backup_one_mod()
l foo_backup_one_mod() : Creates a backup for a single instance of the activity. 在 该例子里,它除了会 backup 该 instance 的 basic info 外,还会调用自定义函数 backup_foo_responses() 来 备份 response .
l foo_check_backup_mods() : 该 函数被 /backup folder 下的 backup libraries 调用。 它 用于生成由所有 instance 的 setting info 构成的 string 。
l foo_check_backup_mods_instances() : foo_check_backup_mods() 会 对每一个 instance 都调用该函数来 生成该 instance 的 setting info string 。该函数还会调用自定义函数 foo_response_ids_by_instance() 来 获取 response count, 并写入 setting info string .
l foo_encode_content_links() : Necessary to support interactivity linking. Ensures that interactivity links stay intact between the backup and restore processes.
l foo_ids() : Returns an array of all of the Foo! IDs for a course. Used by foo_check_backup_mods() .
Backup functions only for foo module
l backup_foo_responses() : Creates the XML output to backup the foo_responses table. Executed from the foo_backup_mods() function.
l foo_response_ids_by_course() : Uses an SQL query to return an array of IDs from the table foo_responses . Called by foo_check_backup_mods() .
l foo_response_ids_by_instance() : Returns an array of IDs for a particular instance of foo from the foo_responses table. Called by foo_check_backup_mods_instances() .
下面是 restorelib.php 的 functions (包括通用 functions and only for foo module functions )
Common restore functions
Common restore functions should be implemented for every activity module.
l foo_restore_mods() : This is the main entry point to the restore code for the module. It is called by core Moodle to perform restores. Calls the foo_responses_restore_mods() function to perform internal restore functions.
l foo_decode_content_links_caller() : Reverses the link encoding from the backup process in order to restore the interactivity links. Iterates through all module content and calls foo_decode_content_links() function where needed to perform the decode. It's called from the restore_decode_content_links() function.
l foo_decode_content_links() : Performs the actual decoding of content in the restore file. Required to support interactivity linking.
l foo_restore_logs() : Returns a log record. Called by restore_log_module() .
l foo_restore_wiki2markdown() : Converts instructions in FORMAT_WIKI to FORMAT_MARKDOWN .
Restore functions only for foo module
l foo_responses_restore_mods() : This function restores the foo_responses table entries and is called by the foo_restore_mods() function.