Moodle开发笔记7-Activity module开发

    技术2022-05-20  100

    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.

     


    最新回复(0)