Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/lesson/locallib.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00029 defined('MOODLE_INTERNAL') || die();
00030 
00032 require_once($CFG->dirroot.'/course/moodleform_mod.php');
00033 require_once($CFG->dirroot . '/mod/lesson/lib.php');
00034 require_once($CFG->libdir . '/filelib.php');
00035 
00037 define('LESSON_THISPAGE', 0);
00039 define("LESSON_UNSEENPAGE", 1);
00041 define("LESSON_UNANSWEREDPAGE", 2);
00043 define("LESSON_NEXTPAGE", -1);
00045 define("LESSON_EOL", -9);
00047 define("LESSON_UNSEENBRANCHPAGE", -50);
00049 define("LESSON_PREVIOUSPAGE", -40);
00051 define("LESSON_RANDOMPAGE", -60);
00053 define("LESSON_RANDOMBRANCH", -70);
00055 define("LESSON_CLUSTERJUMP", -80);
00057 define("LESSON_UNDEFINED", -99);
00058 
00060 define("LESSON_MAX_EVENT_LENGTH", "432000");
00061 
00062 
00066 
00077 function lesson_display_teacher_warning($lesson) {
00078     global $DB;
00079 
00080     // get all of the lesson answers
00081     $params = array ("lessonid" => $lesson->id);
00082     if (!$lessonanswers = $DB->get_records_select("lesson_answers", "lessonid = :lessonid", $params)) {
00083         // no answers, then not using cluster or unseen
00084         return false;
00085     }
00086     // just check for the first one that fulfills the requirements
00087     foreach ($lessonanswers as $lessonanswer) {
00088         if ($lessonanswer->jumpto == LESSON_CLUSTERJUMP || $lessonanswer->jumpto == LESSON_UNSEENBRANCHPAGE) {
00089             return true;
00090         }
00091     }
00092 
00093     // if no answers use either of the two jumps
00094     return false;
00095 }
00096 
00107 function lesson_unseen_question_jump($lesson, $user, $pageid) {
00108     global $DB;
00109 
00110     // get the number of retakes
00111     if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$user))) {
00112         $retakes = 0;
00113     }
00114 
00115     // get all the lesson_attempts aka what the user has seen
00116     if ($viewedpages = $DB->get_records("lesson_attempts", array("lessonid"=>$lesson->id, "userid"=>$user, "retry"=>$retakes), "timeseen DESC")) {
00117         foreach($viewedpages as $viewed) {
00118             $seenpages[] = $viewed->pageid;
00119         }
00120     } else {
00121         $seenpages = array();
00122     }
00123 
00124     // get the lesson pages
00125     $lessonpages = $lesson->load_all_pages();
00126 
00127     if ($pageid == LESSON_UNSEENBRANCHPAGE) {  // this only happens when a student leaves in the middle of an unseen question within a branch series
00128         $pageid = $seenpages[0];  // just change the pageid to the last page viewed inside the branch table
00129     }
00130 
00131     // go up the pages till branch table
00132     while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
00133         if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) {
00134             break;
00135         }
00136         $pageid = $lessonpages[$pageid]->prevpageid;
00137     }
00138 
00139     $pagesinbranch = $lesson->get_sub_pages_of($pageid, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH));
00140 
00141     // this foreach loop stores all the pages that are within the branch table but are not in the $seenpages array
00142     $unseen = array();
00143     foreach($pagesinbranch as $page) {
00144         if (!in_array($page->id, $seenpages)) {
00145             $unseen[] = $page->id;
00146         }
00147     }
00148 
00149     if(count($unseen) == 0) {
00150         if(isset($pagesinbranch)) {
00151             $temp = end($pagesinbranch);
00152             $nextpage = $temp->nextpageid; // they have seen all the pages in the branch, so go to EOB/next branch table/EOL
00153         } else {
00154             // there are no pages inside the branch, so return the next page
00155             $nextpage = $lessonpages[$pageid]->nextpageid;
00156         }
00157         if ($nextpage == 0) {
00158             return LESSON_EOL;
00159         } else {
00160             return $nextpage;
00161         }
00162     } else {
00163         return $unseen[rand(0, count($unseen)-1)];  // returns a random page id for the next page
00164     }
00165 }
00166 
00174 function lesson_unseen_branch_jump($lesson, $userid) {
00175     global $DB;
00176 
00177     if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$userid))) {
00178         $retakes = 0;
00179     }
00180 
00181     $params = array ("lessonid" => $lesson->id, "userid" => $userid, "retry" => $retakes);
00182     if (!$seenbranches = $DB->get_records_select("lesson_branch", "lessonid = :lessonid AND userid = :userid AND retry = :retry", $params,
00183                 "timeseen DESC")) {
00184         print_error('cannotfindrecords', 'lesson');
00185     }
00186 
00187     // get the lesson pages
00188     $lessonpages = $lesson->load_all_pages();
00189 
00190     // this loads all the viewed branch tables into $seen until it finds the branch table with the flag
00191     // which is the branch table that starts the unseenbranch function
00192     $seen = array();
00193     foreach ($seenbranches as $seenbranch) {
00194         if (!$seenbranch->flag) {
00195             $seen[$seenbranch->pageid] = $seenbranch->pageid;
00196         } else {
00197             $start = $seenbranch->pageid;
00198             break;
00199         }
00200     }
00201     // this function searches through the lesson pages to find all the branch tables
00202     // that follow the flagged branch table
00203     $pageid = $lessonpages[$start]->nextpageid; // move down from the flagged branch table
00204     while ($pageid != 0) {  // grab all of the branch table till eol
00205         if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) {
00206             $branchtables[] = $lessonpages[$pageid]->id;
00207         }
00208         $pageid = $lessonpages[$pageid]->nextpageid;
00209     }
00210     $unseen = array();
00211     foreach ($branchtables as $branchtable) {
00212         // load all of the unseen branch tables into unseen
00213         if (!array_key_exists($branchtable, $seen)) {
00214             $unseen[] = $branchtable;
00215         }
00216     }
00217     if (count($unseen) > 0) {
00218         return $unseen[rand(0, count($unseen)-1)];  // returns a random page id for the next page
00219     } else {
00220         return LESSON_EOL;  // has viewed all of the branch tables
00221     }
00222 }
00223 
00231 function lesson_random_question_jump($lesson, $pageid) {
00232     global $DB;
00233 
00234     // get the lesson pages
00235     $params = array ("lessonid" => $lesson->id);
00236     if (!$lessonpages = $DB->get_records_select("lesson_pages", "lessonid = :lessonid", $params)) {
00237         print_error('cannotfindpages', 'lesson');
00238     }
00239 
00240     // go up the pages till branch table
00241     while ($pageid != 0) { // this condition should never be satisfied... only happens if there are no branch tables above this page
00242 
00243         if ($lessonpages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE) {
00244             break;
00245         }
00246         $pageid = $lessonpages[$pageid]->prevpageid;
00247     }
00248 
00249     // get the pages within the branch
00250     $pagesinbranch = $lesson->get_sub_pages_of($pageid, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH));
00251 
00252     if(count($pagesinbranch) == 0) {
00253         // there are no pages inside the branch, so return the next page
00254         return $lessonpages[$pageid]->nextpageid;
00255     } else {
00256         return $pagesinbranch[rand(0, count($pagesinbranch)-1)]->id;  // returns a random page id for the next page
00257     }
00258 }
00259 
00274 function lesson_grade($lesson, $ntries, $userid = 0) {
00275     global $USER, $DB;
00276 
00277     if (empty($userid)) {
00278         $userid = $USER->id;
00279     }
00280 
00281     // Zero out everything
00282     $ncorrect     = 0;
00283     $nviewed      = 0;
00284     $score        = 0;
00285     $nmanual      = 0;
00286     $manualpoints = 0;
00287     $thegrade     = 0;
00288     $nquestions   = 0;
00289     $total        = 0;
00290     $earned       = 0;
00291 
00292     $params = array ("lessonid" => $lesson->id, "userid" => $userid, "retry" => $ntries);
00293     if ($useranswers = $DB->get_records_select("lesson_attempts",  "lessonid = :lessonid AND
00294             userid = :userid AND retry = :retry", $params, "timeseen")) {
00295         // group each try with its page
00296         $attemptset = array();
00297         foreach ($useranswers as $useranswer) {
00298             $attemptset[$useranswer->pageid][] = $useranswer;
00299         }
00300 
00301         // Drop all attempts that go beyond max attempts for the lesson
00302         foreach ($attemptset as $key => $set) {
00303             $attemptset[$key] = array_slice($set, 0, $lesson->maxattempts);
00304         }
00305 
00306         // get only the pages and their answers that the user answered
00307         list($usql, $parameters) = $DB->get_in_or_equal(array_keys($attemptset));
00308         array_unshift($parameters, $lesson->id);
00309         $pages = $DB->get_records_select("lesson_pages", "lessonid = ? AND id $usql", $parameters);
00310         $answers = $DB->get_records_select("lesson_answers", "lessonid = ? AND pageid $usql", $parameters);
00311 
00312         // Number of pages answered
00313         $nquestions = count($pages);
00314 
00315         foreach ($attemptset as $attempts) {
00316             $page = lesson_page::load($pages[end($attempts)->pageid], $lesson);
00317             if ($lesson->custom) {
00318                 $attempt = end($attempts);
00319                 // If essay question, handle it, otherwise add to score
00320                 if ($page->requires_manual_grading()) {
00321                     $useranswerobj = unserialize($attempt->useranswer);
00322                     if (isset($useranswerobj->score)) {
00323                         $earned += $useranswerobj->score;
00324                     }
00325                     $nmanual++;
00326                     $manualpoints += $answers[$attempt->answerid]->score;
00327                 } else if (!empty($attempt->answerid)) {
00328                     $earned += $page->earned_score($answers, $attempt);
00329                 }
00330             } else {
00331                 foreach ($attempts as $attempt) {
00332                     $earned += $attempt->correct;
00333                 }
00334                 $attempt = end($attempts); // doesn't matter which one
00335                 // If essay question, increase numbers
00336                 if ($page->requires_manual_grading()) {
00337                     $nmanual++;
00338                     $manualpoints++;
00339                 }
00340             }
00341             // Number of times answered
00342             $nviewed += count($attempts);
00343         }
00344 
00345         if ($lesson->custom) {
00346             $bestscores = array();
00347             // Find the highest possible score per page to get our total
00348             foreach ($answers as $answer) {
00349                 if(!isset($bestscores[$answer->pageid])) {
00350                     $bestscores[$answer->pageid] = $answer->score;
00351                 } else if ($bestscores[$answer->pageid] < $answer->score) {
00352                     $bestscores[$answer->pageid] = $answer->score;
00353                 }
00354             }
00355             $total = array_sum($bestscores);
00356         } else {
00357             // Check to make sure the student has answered the minimum questions
00358             if ($lesson->minquestions and $nquestions < $lesson->minquestions) {
00359                 // Nope, increase number viewed by the amount of unanswered questions
00360                 $total =  $nviewed + ($lesson->minquestions - $nquestions);
00361             } else {
00362                 $total = $nviewed;
00363             }
00364         }
00365     }
00366 
00367     if ($total) { // not zero
00368         $thegrade = round(100 * $earned / $total, 5);
00369     }
00370 
00371     // Build the grade information object
00372     $gradeinfo               = new stdClass;
00373     $gradeinfo->nquestions   = $nquestions;
00374     $gradeinfo->attempts     = $nviewed;
00375     $gradeinfo->total        = $total;
00376     $gradeinfo->earned       = $earned;
00377     $gradeinfo->grade        = $thegrade;
00378     $gradeinfo->nmanual      = $nmanual;
00379     $gradeinfo->manualpoints = $manualpoints;
00380 
00381     return $gradeinfo;
00382 }
00383 
00392 function lesson_displayleftif($lesson) {
00393     global $CFG, $USER, $DB;
00394 
00395     if (!empty($lesson->displayleftif)) {
00396         // get the current user's max grade for this lesson
00397         $params = array ("userid" => $USER->id, "lessonid" => $lesson->id);
00398         if ($maxgrade = $DB->get_record_sql('SELECT userid, MAX(grade) AS maxgrade FROM {lesson_grades} WHERE userid = :userid AND lessonid = :lessonid GROUP BY userid', $params)) {
00399             if ($maxgrade->maxgrade < $lesson->displayleftif) {
00400                 return 0;  // turn off the displayleft
00401             }
00402         } else {
00403             return 0; // no grades
00404         }
00405     }
00406 
00407     // if we get to here, keep the original state of displayleft lesson setting
00408     return $lesson->displayleft;
00409 }
00410 
00418 function lesson_add_fake_blocks($page, $cm, $lesson, $timer = null) {
00419     $bc = lesson_menu_block_contents($cm->id, $lesson);
00420     if (!empty($bc)) {
00421         $regions = $page->blocks->get_regions();
00422         $firstregion = reset($regions);
00423         $page->blocks->add_fake_block($bc, $firstregion);
00424     }
00425 
00426     $bc = lesson_mediafile_block_contents($cm->id, $lesson);
00427     if (!empty($bc)) {
00428         $page->blocks->add_fake_block($bc, $page->blocks->get_default_region());
00429     }
00430 
00431     if (!empty($timer)) {
00432         $bc = lesson_clock_block_contents($cm->id, $lesson, $timer, $page);
00433         if (!empty($bc)) {
00434             $page->blocks->add_fake_block($bc, $page->blocks->get_default_region());
00435         }
00436     }
00437 }
00438 
00447 function lesson_mediafile_block_contents($cmid, $lesson) {
00448     global $OUTPUT;
00449     if (empty($lesson->mediafile)) {
00450         return null;
00451     }
00452 
00453     $options = array();
00454     $options['menubar'] = 0;
00455     $options['location'] = 0;
00456     $options['left'] = 5;
00457     $options['top'] = 5;
00458     $options['scrollbars'] = 1;
00459     $options['resizable'] = 1;
00460     $options['width'] = $lesson->mediawidth;
00461     $options['height'] = $lesson->mediaheight;
00462 
00463     $link = new moodle_url('/mod/lesson/mediafile.php?id='.$cmid);
00464     $action = new popup_action('click', $link, 'lessonmediafile', $options);
00465     $content = $OUTPUT->action_link($link, get_string('mediafilepopup', 'lesson'), $action, array('title'=>get_string('mediafilepopup', 'lesson')));
00466 
00467     $bc = new block_contents();
00468     $bc->title = get_string('linkedmedia', 'lesson');
00469     $bc->attributes['class'] = 'mediafile';
00470     $bc->content = $content;
00471 
00472     return $bc;
00473 }
00474 
00484 function lesson_clock_block_contents($cmid, $lesson, $timer, $page) {
00485     // Display for timed lessons and for students only
00486     $context = get_context_instance(CONTEXT_MODULE, $cmid);
00487     if(!$lesson->timed || has_capability('mod/lesson:manage', $context)) {
00488         return null;
00489     }
00490 
00491     $content = '<div class="jshidewhenenabled">';
00492     $content .=  $lesson->time_remaining($timer->starttime);
00493     $content .= '</div>';
00494 
00495     $clocksettings = array('starttime'=>$timer->starttime, 'servertime'=>time(),'testlength'=>($lesson->maxtime * 60));
00496     $page->requires->data_for_js('clocksettings', $clocksettings);
00497     $page->requires->js('/mod/lesson/timer.js');
00498     $page->requires->js_function_call('show_clock');
00499 
00500     $bc = new block_contents();
00501     $bc->title = get_string('timeremaining', 'lesson');
00502     $bc->attributes['class'] = 'clock block';
00503     $bc->content = $content;
00504 
00505     return $bc;
00506 }
00507 
00516 function lesson_menu_block_contents($cmid, $lesson) {
00517     global $CFG, $DB;
00518 
00519     if (!$lesson->displayleft) {
00520         return null;
00521     }
00522 
00523     $pages = $lesson->load_all_pages();
00524     foreach ($pages as $page) {
00525         if ((int)$page->prevpageid === 0) {
00526             $pageid = $page->id;
00527             break;
00528         }
00529     }
00530     $currentpageid = optional_param('pageid', $pageid, PARAM_INT);
00531 
00532     if (!$pageid || !$pages) {
00533         return null;
00534     }
00535 
00536     $content = '<a href="#maincontent" class="skip">'.get_string('skip', 'lesson')."</a>\n<div class=\"menuwrapper\">\n<ul>\n";
00537 
00538     while ($pageid != 0) {
00539         $page = $pages[$pageid];
00540 
00541         // Only process branch tables with display turned on
00542         if ($page->displayinmenublock && $page->display) {
00543             if ($page->id == $currentpageid) {
00544                 $content .= '<li class="selected">'.format_string($page->title,true)."</li>\n";
00545             } else {
00546                 $content .= "<li class=\"notselected\"><a href=\"$CFG->wwwroot/mod/lesson/view.php?id=$cmid&amp;pageid=$page->id\">".format_string($page->title,true)."</a></li>\n";
00547             }
00548 
00549         }
00550         $pageid = $page->nextpageid;
00551     }
00552     $content .= "</ul>\n</div>\n";
00553 
00554     $bc = new block_contents();
00555     $bc->title = get_string('lessonmenu', 'lesson');
00556     $bc->attributes['class'] = 'menu block';
00557     $bc->content = $content;
00558 
00559     return $bc;
00560 }
00561 
00570 function lesson_add_header_buttons($cm, $context, $extraeditbuttons=false, $lessonpageid=null) {
00571     global $CFG, $PAGE, $OUTPUT;
00572     if (has_capability('mod/lesson:edit', $context) && $extraeditbuttons) {
00573         if ($lessonpageid === null) {
00574             print_error('invalidpageid', 'lesson');
00575         }
00576         if (!empty($lessonpageid) && $lessonpageid != LESSON_EOL) {
00577             $url = new moodle_url('/mod/lesson/editpage.php', array('id'=>$cm->id, 'pageid'=>$lessonpageid, 'edit'=>1));
00578             $PAGE->set_button($OUTPUT->single_button($url, get_string('editpagecontent', 'lesson')));
00579         }
00580     }
00581 }
00582 
00592 function lesson_get_media_html($lesson, $context) {
00593     global $CFG, $PAGE, $OUTPUT;
00594     require_once("$CFG->libdir/resourcelib.php");
00595 
00596     // get the media file link
00597     if (strpos($lesson->mediafile, '://') !== false) {
00598         $url = new moodle_url($lesson->mediafile);
00599     } else {
00600         // the timemodified is used to prevent caching problems, instead of '/' we should better read from files table and use sortorder
00601         $url = moodle_url::make_pluginfile_url($context->id, 'mod_lesson', 'mediafile', $lesson->timemodified, '/', ltrim($lesson->mediafile, '/'));
00602     }
00603     $title = $lesson->mediafile;
00604 
00605     $clicktoopen = html_writer::link($url, get_string('download'));
00606 
00607     $mimetype = resourcelib_guess_url_mimetype($url);
00608 
00609     $extension = resourcelib_get_extension($url->out(false));
00610 
00611     // find the correct type and print it out
00612     if (in_array($mimetype, array('image/gif','image/jpeg','image/png'))) {  // It's an image
00613         $code = resourcelib_embed_image($url, $title);
00614 
00615     } else if ($mimetype == 'audio/mp3') {
00616         // MP3 audio file
00617         $code = resourcelib_embed_mp3($url, $title, $clicktoopen);
00618 
00619     } else if ($mimetype == 'video/x-flv' or $extension === 'f4v') {
00620         // Flash video file
00621         $code = resourcelib_embed_flashvideo($url, $title, $clicktoopen);
00622 
00623     } else if ($mimetype == 'application/x-shockwave-flash') {
00624         // Flash file
00625         $code = resourcelib_embed_flash($url, $title, $clicktoopen);
00626 
00627     } else if (substr($mimetype, 0, 10) == 'video/x-ms') {
00628         // Windows Media Player file
00629         $code = resourcelib_embed_mediaplayer($url, $title, $clicktoopen);
00630 
00631     } else if ($mimetype == 'video/quicktime') {
00632         // Quicktime file
00633         $code = resourcelib_embed_quicktime($url, $title, $clicktoopen);
00634 
00635     } else if ($mimetype == 'video/mpeg') {
00636         // Mpeg file
00637         $code = resourcelib_embed_mpeg($url, $title, $clicktoopen);
00638 
00639     } else if ($mimetype == 'audio/x-pn-realaudio-plugin') {
00640         // RealMedia file
00641         $code = resourcelib_embed_real($url, $title, $clicktoopen);
00642 
00643     } else {
00644         // anything else - just try object tag enlarged as much as possible
00645         $code = resourcelib_embed_general($url, $title, $clicktoopen, $mimetype);
00646     }
00647 
00648     return $code;
00649 }
00650 
00651 
00664 abstract class lesson_add_page_form_base extends moodleform {
00665 
00671     public $qtype;
00672 
00677     public $qtypestring;
00678 
00683     protected $editoroptions = array();
00684 
00690     protected $standard = true;
00691 
00696     public function custom_definition() {}
00697 
00702     public final function is_standard() {
00703         return (bool)$this->standard;
00704     }
00705 
00712     public final function definition() {
00713         $mform = $this->_form;
00714         $editoroptions = $this->_customdata['editoroptions'];
00715 
00716         $mform->addElement('header', 'qtypeheading', get_string('addaquestionpage', 'lesson', get_string($this->qtypestring, 'lesson')));
00717 
00718         $mform->addElement('hidden', 'id');
00719         $mform->setType('id', PARAM_INT);
00720 
00721         $mform->addElement('hidden', 'pageid');
00722         $mform->setType('pageid', PARAM_INT);
00723 
00724         if ($this->standard === true) {
00725             $mform->addElement('hidden', 'qtype');
00726             $mform->setType('qtype', PARAM_INT);
00727 
00728             $mform->addElement('text', 'title', get_string('pagetitle', 'lesson'), array('size'=>70));
00729             $mform->setType('title', PARAM_TEXT);
00730             $mform->addRule('title', get_string('required'), 'required', null, 'client');
00731 
00732             $this->editoroptions = array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$this->_customdata['maxbytes']);
00733             $mform->addElement('editor', 'contents_editor', get_string('pagecontents', 'lesson'), null, $this->editoroptions);
00734             $mform->setType('contents_editor', PARAM_RAW);
00735             $mform->addRule('contents_editor', get_string('required'), 'required', null, 'client');
00736         }
00737 
00738         $this->custom_definition();
00739 
00740         if ($this->_customdata['edit'] === true) {
00741             $mform->addElement('hidden', 'edit', 1);
00742             $this->add_action_buttons(get_string('cancel'), get_string('savepage', 'lesson'));
00743         } else {
00744             $this->add_action_buttons(get_string('cancel'), get_string('addaquestionpage', 'lesson'));
00745         }
00746     }
00747 
00755     protected final function add_jumpto($name, $label=null, $selected=LESSON_NEXTPAGE) {
00756         $title = get_string("jump", "lesson");
00757         if ($label === null) {
00758             $label = $title;
00759         }
00760         if (is_int($name)) {
00761             $name = "jumpto[$name]";
00762         }
00763         $this->_form->addElement('select', $name, $label, $this->_customdata['jumpto']);
00764         $this->_form->setDefault($name, $selected);
00765         $this->_form->addHelpButton($name, 'jumps', 'lesson');
00766     }
00767 
00775     protected final function add_score($name, $label=null, $value=null) {
00776         if ($label === null) {
00777             $label = get_string("score", "lesson");
00778         }
00779         if (is_int($name)) {
00780             $name = "score[$name]";
00781         }
00782         $this->_form->addElement('text', $name, $label, array('size'=>5));
00783         if ($value !== null) {
00784             $this->_form->setDefault($name, $value);
00785         }
00786     }
00787 
00796     protected final function add_answer($count, $label = NULL, $required = false) {
00797         if ($label === NULL) {
00798             $label = get_string('answer', 'lesson');
00799         }
00800         $this->_form->addElement('editor', 'answer_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
00801         $this->_form->setDefault('answer_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE));
00802         if ($required) {
00803             $this->_form->addRule('answer_editor['.$count.']', get_string('required'), 'required', null, 'client');
00804         }
00805     }
00814     protected final function add_response($count, $label = NULL, $required = false) {
00815         if ($label === NULL) {
00816             $label = get_string('response', 'lesson');
00817         }
00818         $this->_form->addElement('editor', 'response_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
00819         $this->_form->setDefault('response_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE));
00820         if ($required) {
00821             $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client');
00822         }
00823     }
00824 
00833     public function construction_override() {
00834         return true;
00835     }
00836 }
00837 
00838 
00839 
00902 class lesson extends lesson_base {
00903 
00909     protected $firstpageid = null;
00915     protected $lastpageid = null;
00924     protected $pages = array();
00930     protected $loadedallpages = false;
00931 
00939     public static function create($properties) {
00940         return new lesson($properties);
00941     }
00942 
00949     public static function load($lessonid) {
00950         global $DB;
00951 
00952         if (!$lesson = $DB->get_record('lesson', array('id' => $lessonid))) {
00953             print_error('invalidcoursemodule');
00954         }
00955         return new lesson($lesson);
00956     }
00957 
00961     public function delete() {
00962         global $CFG, $DB;
00963         require_once($CFG->libdir.'/gradelib.php');
00964         require_once($CFG->dirroot.'/calendar/lib.php');
00965 
00966         $DB->delete_records("lesson", array("id"=>$this->properties->id));;
00967         $DB->delete_records("lesson_pages", array("lessonid"=>$this->properties->id));
00968         $DB->delete_records("lesson_answers", array("lessonid"=>$this->properties->id));
00969         $DB->delete_records("lesson_attempts", array("lessonid"=>$this->properties->id));
00970         $DB->delete_records("lesson_grades", array("lessonid"=>$this->properties->id));
00971         $DB->delete_records("lesson_timer", array("lessonid"=>$this->properties->id));
00972         $DB->delete_records("lesson_branch", array("lessonid"=>$this->properties->id));
00973         $DB->delete_records("lesson_high_scores", array("lessonid"=>$this->properties->id));
00974         if ($events = $DB->get_records('event', array("modulename"=>'lesson', "instance"=>$this->properties->id))) {
00975             foreach($events as $event) {
00976                 $event = calendar_event::load($event);
00977                 $event->delete();
00978             }
00979         }
00980 
00981         grade_update('mod/lesson', $this->properties->course, 'mod', 'lesson', $this->properties->id, 0, NULL, array('deleted'=>1));
00982         return true;
00983     }
00984 
00996     protected function get_messages() {
00997         global $SESSION;
00998 
00999         $messages = array();
01000         if (!empty($SESSION->lesson_messages) && is_array($SESSION->lesson_messages) && array_key_exists($this->properties->id, $SESSION->lesson_messages)) {
01001             $messages = $SESSION->lesson_messages[$this->properties->id];
01002             unset($SESSION->lesson_messages[$this->properties->id]);
01003         }
01004 
01005         return $messages;
01006     }
01007 
01017     public function get_attempts($retries, $correct=false, $pageid=null, $userid=null) {
01018         global $USER, $DB;
01019         $params = array("lessonid"=>$this->properties->id, "userid"=>$userid, "retry"=>$retries);
01020         if ($correct) {
01021             $params['correct'] = 1;
01022         }
01023         if ($pageid !== null) {
01024             $params['pageid'] = $pageid;
01025         }
01026         if ($userid === null) {
01027             $params['userid'] = $USER->id;
01028         }
01029         return $DB->get_records('lesson_attempts', $params, 'timeseen ASC');
01030     }
01031 
01042     protected function get_firstpage() {
01043         $pages = $this->load_all_pages();
01044         if (count($pages) > 0) {
01045             foreach ($pages as $page) {
01046                 if ((int)$page->prevpageid === 0) {
01047                     return $page;
01048                 }
01049             }
01050         }
01051         return false;
01052     }
01053 
01064     protected function get_lastpage() {
01065         $pages = $this->load_all_pages();
01066         if (count($pages) > 0) {
01067             foreach ($pages as $page) {
01068                 if ((int)$page->nextpageid === 0) {
01069                     return $page;
01070                 }
01071             }
01072         }
01073         return false;
01074     }
01075 
01080     protected function get_firstpageid() {
01081         global $DB;
01082         if ($this->firstpageid == null) {
01083             if (!$this->loadedallpages) {
01084                 $firstpageid = $DB->get_field('lesson_pages', 'id', array('lessonid'=>$this->properties->id, 'prevpageid'=>0));
01085                 if (!$firstpageid) {
01086                     print_error('cannotfindfirstpage', 'lesson');
01087                 }
01088                 $this->firstpageid = $firstpageid;
01089             } else {
01090                 $firstpage = $this->get_firstpage();
01091                 $this->firstpageid = $firstpage->id;
01092             }
01093         }
01094         return $this->firstpageid;
01095     }
01096 
01101     public function get_lastpageid() {
01102         global $DB;
01103         if ($this->lastpageid == null) {
01104             if (!$this->loadedallpages) {
01105                 $lastpageid = $DB->get_field('lesson_pages', 'id', array('lessonid'=>$this->properties->id, 'nextpageid'=>0));
01106                 if (!$lastpageid) {
01107                     print_error('cannotfindlastpage', 'lesson');
01108                 }
01109                 $this->lastpageid = $lastpageid;
01110             } else {
01111                 $lastpageid = $this->get_lastpage();
01112                 $this->lastpageid = $lastpageid->id;
01113             }
01114         }
01115 
01116         return $this->lastpageid;
01117     }
01118 
01124     public function get_next_page($nextpageid) {
01125         global $USER, $DB;
01126         $allpages = $this->load_all_pages();
01127         if ($this->properties->nextpagedefault) {
01128             // in Flash Card mode...first get number of retakes
01129             $nretakes = $DB->count_records("lesson_grades", array("lessonid" => $this->properties->id, "userid" => $USER->id));
01130             shuffle($allpages);
01131             $found = false;
01132             if ($this->properties->nextpagedefault == LESSON_UNSEENPAGE) {
01133                 foreach ($allpages as $nextpage) {
01134                     if (!$DB->count_records("lesson_attempts", array("pageid" => $nextpage->id, "userid" => $USER->id, "retry" => $nretakes))) {
01135                         $found = true;
01136                         break;
01137                     }
01138                 }
01139             } elseif ($this->properties->nextpagedefault == LESSON_UNANSWEREDPAGE) {
01140                 foreach ($allpages as $nextpage) {
01141                     if (!$DB->count_records("lesson_attempts", array('pageid' => $nextpage->id, 'userid' => $USER->id, 'correct' => 1, 'retry' => $nretakes))) {
01142                         $found = true;
01143                         break;
01144                     }
01145                 }
01146             }
01147             if ($found) {
01148                 if ($this->properties->maxpages) {
01149                     // check number of pages viewed (in the lesson)
01150                     if ($DB->count_records("lesson_attempts", array("lessonid" => $this->properties->id, "userid" => $USER->id, "retry" => $nretakes)) >= $this->properties->maxpages) {
01151                         return LESSON_EOL;
01152                     }
01153                 }
01154                 return $nextpage->id;
01155             }
01156         }
01157         // In a normal lesson mode
01158         foreach ($allpages as $nextpage) {
01159             if ((int)$nextpage->id === (int)$nextpageid) {
01160                 return $nextpage->id;
01161             }
01162         }
01163         return LESSON_EOL;
01164     }
01165 
01175     public function add_message($message, $class="notifyproblem", $align='center') {
01176         global $SESSION;
01177 
01178         if (empty($SESSION->lesson_messages) || !is_array($SESSION->lesson_messages)) {
01179             $SESSION->lesson_messages = array();
01180             $SESSION->lesson_messages[$this->properties->id] = array();
01181         } else if (!array_key_exists($this->properties->id, $SESSION->lesson_messages)) {
01182             $SESSION->lesson_messages[$this->properties->id] = array();
01183         }
01184 
01185         $SESSION->lesson_messages[$this->properties->id][] = array($message, $class, $align);
01186 
01187         return true;
01188     }
01189 
01194     public function is_accessible() {
01195         $available = $this->properties->available;
01196         $deadline = $this->properties->deadline;
01197         return (($available == 0 || time() >= $available) && ($deadline == 0 || time() < $deadline));
01198     }
01199 
01204     public function start_timer() {
01205         global $USER, $DB;
01206         $USER->startlesson[$this->properties->id] = true;
01207         $startlesson = new stdClass;
01208         $startlesson->lessonid = $this->properties->id;
01209         $startlesson->userid = $USER->id;
01210         $startlesson->starttime = time();
01211         $startlesson->lessontime = time();
01212         $DB->insert_record('lesson_timer', $startlesson);
01213         if ($this->properties->timed) {
01214             $this->add_message(get_string('maxtimewarning', 'lesson', $this->properties->maxtime), 'center');
01215         }
01216         return true;
01217     }
01218 
01226     public function update_timer($restart=false, $continue=false) {
01227         global $USER, $DB;
01228         // clock code
01229         // get time information for this user
01230         if (!$timer = $DB->get_records('lesson_timer', array ("lessonid" => $this->properties->id, "userid" => $USER->id), 'starttime DESC', '*', 0, 1)) {
01231             print_error('cannotfindtimer', 'lesson');
01232         } else {
01233             $timer = current($timer); // this will get the latest start time record
01234         }
01235 
01236         if ($restart) {
01237             if ($continue) {
01238                 // continue a previous test, need to update the clock  (think this option is disabled atm)
01239                 $timer->starttime = time() - ($timer->lessontime - $timer->starttime);
01240             } else {
01241                 // starting over, so reset the clock
01242                 $timer->starttime = time();
01243             }
01244         }
01245 
01246         $timer->lessontime = time();
01247         $DB->update_record('lesson_timer', $timer);
01248         return $timer;
01249     }
01250 
01255     public function stop_timer() {
01256         global $USER, $DB;
01257         unset($USER->startlesson[$this->properties->id]);
01258         return $this->update_timer(false, false);
01259     }
01260 
01264     public function has_pages() {
01265         global $DB;
01266         $pagecount = $DB->count_records('lesson_pages', array('lessonid'=>$this->properties->id));
01267         return ($pagecount>0);
01268     }
01269 
01274     public function link_for_activitylink() {
01275         global $DB;
01276         $module = $DB->get_record('course_modules', array('id' => $this->properties->activitylink));
01277         if ($module) {
01278             $modname = $DB->get_field('modules', 'name', array('id' => $module->module));
01279             if ($modname) {
01280                 $instancename = $DB->get_field($modname, 'name', array('id' => $module->instance));
01281                 if ($instancename) {
01282                     return html_writer::link(new moodle_url('/mod/'.$modname.'/view.php', array('id'=>$this->properties->activitylink)),
01283                         get_string('activitylinkname', 'lesson', $instancename),
01284                         array('class'=>'centerpadded lessonbutton standardbutton'));
01285                 }
01286             }
01287         }
01288         return '';
01289     }
01290 
01302     public function load_page($pageid) {
01303         if (!array_key_exists($pageid, $this->pages)) {
01304             $manager = lesson_page_type_manager::get($this);
01305             $this->pages[$pageid] = $manager->load_page($pageid, $this);
01306         }
01307         return $this->pages[$pageid];
01308     }
01309 
01315     public function load_all_pages() {
01316         if (!$this->loadedallpages) {
01317             $manager = lesson_page_type_manager::get($this);
01318             $this->pages = $manager->load_all_pages($this);
01319             $this->loadedallpages = true;
01320         }
01321         return $this->pages;
01322     }
01323 
01334     public function jumpto_is_correct($pageid, $jumpto) {
01335         global $DB;
01336 
01337         // first test the special values
01338         if (!$jumpto) {
01339             // same page
01340             return false;
01341         } elseif ($jumpto == LESSON_NEXTPAGE) {
01342             return true;
01343         } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) {
01344             return true;
01345         } elseif ($jumpto == LESSON_RANDOMPAGE) {
01346             return true;
01347         } elseif ($jumpto == LESSON_CLUSTERJUMP) {
01348             return true;
01349         } elseif ($jumpto == LESSON_EOL) {
01350             return true;
01351         }
01352 
01353         $pages = $this->load_all_pages();
01354         $apageid = $pages[$pageid]->nextpageid;
01355         while ($apageid != 0) {
01356             if ($jumpto == $apageid) {
01357                 return true;
01358             }
01359             $apageid = $pages[$apageid]->nextpageid;
01360         }
01361         return false;
01362     }
01363 
01369     public function time_remaining($starttime) {
01370         $timeleft = $starttime + $this->maxtime * 60 - time();
01371         $hours = floor($timeleft/3600);
01372         $timeleft = $timeleft - ($hours * 3600);
01373         $minutes = floor($timeleft/60);
01374         $secs = $timeleft - ($minutes * 60);
01375 
01376         if ($minutes < 10) {
01377             $minutes = "0$minutes";
01378         }
01379         if ($secs < 10) {
01380             $secs = "0$secs";
01381         }
01382         $output   = array();
01383         $output[] = $hours;
01384         $output[] = $minutes;
01385         $output[] = $secs;
01386         $output = implode(':', $output);
01387         return $output;
01388     }
01389 
01403     public function cluster_jump($pageid, $userid=null) {
01404         global $DB, $USER;
01405 
01406         if ($userid===null) {
01407             $userid = $USER->id;
01408         }
01409         // get the number of retakes
01410         if (!$retakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->properties->id, "userid"=>$userid))) {
01411             $retakes = 0;
01412         }
01413         // get all the lesson_attempts aka what the user has seen
01414         $seenpages = array();
01415         if ($attempts = $this->get_attempts($retakes)) {
01416             foreach ($attempts as $attempt) {
01417                 $seenpages[$attempt->pageid] = $attempt->pageid;
01418             }
01419 
01420         }
01421 
01422         // get the lesson pages
01423         $lessonpages = $this->load_all_pages();
01424         // find the start of the cluster
01425         while ($pageid != 0) { // this condition should not be satisfied... should be a cluster page
01426             if ($lessonpages[$pageid]->qtype == LESSON_PAGE_CLUSTER) {
01427                 break;
01428             }
01429             $pageid = $lessonpages[$pageid]->prevpageid;
01430         }
01431 
01432         $clusterpages = array();
01433         $clusterpages = $this->get_sub_pages_of($pageid, array(LESSON_PAGE_ENDOFCLUSTER));
01434         $unseen = array();
01435         foreach ($clusterpages as $key=>$cluster) {
01436             if ($cluster->type !== lesson_page::TYPE_QUESTION) {
01437                 unset($clusterpages[$key]);
01438             } elseif ($cluster->is_unseen($seenpages)) {
01439                 $unseen[] = $cluster;
01440             }
01441         }
01442 
01443         if (count($unseen) > 0) {
01444             // it does not contain elements, then use exitjump, otherwise find out next page/branch
01445             $nextpage = $unseen[rand(0, count($unseen)-1)];
01446             if ($nextpage->qtype == LESSON_PAGE_BRANCHTABLE) {
01447                 // if branch table, then pick a random page inside of it
01448                 $branchpages = $this->get_sub_pages_of($nextpage->id, array(LESSON_PAGE_BRANCHTABLE, LESSON_PAGE_ENDOFBRANCH));
01449                 return $branchpages[rand(0, count($branchpages)-1)]->id;
01450             } else { // otherwise, return the page's id
01451                 return $nextpage->id;
01452             }
01453         } else {
01454             // seen all there is to see, leave the cluster
01455             if (end($clusterpages)->nextpageid == 0) {
01456                 return LESSON_EOL;
01457             } else {
01458                 $clusterendid = $pageid;
01459                 while ($clusterendid != 0) { // this condition should not be satisfied... should be a cluster page
01460                     if ($lessonpages[$clusterendid]->qtype == LESSON_PAGE_CLUSTER) {
01461                         break;
01462                     }
01463                     $clusterendid = $lessonpages[$clusterendid]->prevpageid;
01464                 }
01465                 $exitjump = $DB->get_field("lesson_answers", "jumpto", array("pageid" => $clusterendid, "lessonid" => $this->properties->id));
01466                 if ($exitjump == LESSON_NEXTPAGE) {
01467                     $exitjump = $lessonpages[$pageid]->nextpageid;
01468                 }
01469                 if ($exitjump == 0) {
01470                     return LESSON_EOL;
01471                 } else if (in_array($exitjump, array(LESSON_EOL, LESSON_PREVIOUSPAGE))) {
01472                     return $exitjump;
01473                 } else {
01474                     if (!array_key_exists($exitjump, $lessonpages)) {
01475                         $found = false;
01476                         foreach ($lessonpages as $page) {
01477                             if ($page->id === $clusterendid) {
01478                                 $found = true;
01479                             } else if ($page->qtype == LESSON_PAGE_ENDOFCLUSTER) {
01480                                 $exitjump = $DB->get_field("lesson_answers", "jumpto", array("pageid" => $page->id, "lessonid" => $this->properties->id));
01481                                 break;
01482                             }
01483                         }
01484                     }
01485                     if (!array_key_exists($exitjump, $lessonpages)) {
01486                         return LESSON_EOL;
01487                     }
01488                     return $exitjump;
01489                 }
01490             }
01491         }
01492     }
01493 
01503     public function get_sub_pages_of($pageid, array $ends) {
01504         $lessonpages = $this->load_all_pages();
01505         $pageid = $lessonpages[$pageid]->nextpageid;  // move to the first page after the branch table
01506         $pages = array();
01507 
01508         while (true) {
01509             if ($pageid == 0 || in_array($lessonpages[$pageid]->qtype, $ends)) {
01510                 break;
01511             }
01512             $pages[] = $lessonpages[$pageid];
01513             $pageid = $lessonpages[$pageid]->nextpageid;
01514         }
01515 
01516         return $pages;
01517     }
01518 
01529     public function is_sub_page_of_type($pageid, array $types, array $ends) {
01530         $pages = $this->load_all_pages();
01531         $pageid = $pages[$pageid]->prevpageid; // move up one
01532 
01533         array_unshift($ends, 0);
01534         // go up the pages till branch table
01535         while (true) {
01536             if ($pageid==0 || in_array($pages[$pageid]->qtype, $ends)) {
01537                 return false;
01538             } else if (in_array($pages[$pageid]->qtype, $types)) {
01539                 return true;
01540             }
01541             $pageid = $pages[$pageid]->prevpageid;
01542         }
01543     }
01544 }
01545 
01546 
01560 abstract class lesson_base {
01561 
01566     protected $properties;
01567 
01572     public function __construct($properties) {
01573         $this->properties = (object)$properties;
01574     }
01575 
01585     public function __set($key, $value) {
01586         if (method_exists($this, 'set_'.$key)) {
01587             $this->{'set_'.$key}($value);
01588         }
01589         $this->properties->{$key} = $value;
01590     }
01591 
01601     public function __get($key) {
01602         if (method_exists($this, 'get_'.$key)) {
01603             return $this->{'get_'.$key}();
01604         }
01605         return $this->properties->{$key};
01606     }
01607 
01615     public function __isset($key) {
01616         if (method_exists($this, 'get_'.$key)) {
01617             $val = $this->{'get_'.$key}();
01618             return !empty($val);
01619         }
01620         return !empty($this->properties->{$key});
01621     }
01622 
01626     public static function create() {}
01630     public static function load() {}
01635     public function properties() {
01636         return $this->properties;
01637     }
01638 }
01639 
01640 
01678 abstract class lesson_page extends lesson_base {
01679 
01684     protected $lesson = null;
01689     protected $answers = null;
01694     protected $type = 0;
01695 
01699     const TYPE_QUESTION = 0;
01700     const TYPE_STRUCTURE = 1;
01701 
01708     abstract protected function get_typeid();
01714     abstract protected function get_typestring();
01715 
01723     abstract public function display($renderer, $attempt);
01724 
01735     final public static function create($properties, lesson $lesson, $context, $maxbytes) {
01736         global $DB;
01737         $newpage = new stdClass;
01738         $newpage->title = $properties->title;
01739         $newpage->contents = $properties->contents_editor['text'];
01740         $newpage->contentsformat = $properties->contents_editor['format'];
01741         $newpage->lessonid = $lesson->id;
01742         $newpage->timecreated = time();
01743         $newpage->qtype = $properties->qtype;
01744         $newpage->qoption = (isset($properties->qoption))?1:0;
01745         $newpage->layout = (isset($properties->layout))?1:0;
01746         $newpage->display = (isset($properties->display))?1:0;
01747         $newpage->prevpageid = 0; // this is a first page
01748         $newpage->nextpageid = 0; // this is the only page
01749 
01750         if ($properties->pageid) {
01751             $prevpage = $DB->get_record("lesson_pages", array("id" => $properties->pageid), 'id, nextpageid');
01752             if (!$prevpage) {
01753                 print_error('cannotfindpages', 'lesson');
01754             }
01755             $newpage->prevpageid = $prevpage->id;
01756             $newpage->nextpageid = $prevpage->nextpageid;
01757         } else {
01758             $nextpage = $DB->get_record('lesson_pages', array('lessonid'=>$lesson->id, 'prevpageid'=>0), 'id');
01759             if ($nextpage) {
01760                 // This is the first page, there are existing pages put this at the start
01761                 $newpage->nextpageid = $nextpage->id;
01762             }
01763         }
01764 
01765         $newpage->id = $DB->insert_record("lesson_pages", $newpage);
01766 
01767         $editor = new stdClass;
01768         $editor->id = $newpage->id;
01769         $editor->contents_editor = $properties->contents_editor;
01770         $editor = file_postupdate_standard_editor($editor, 'contents', array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$maxbytes), $context, 'mod_lesson', 'page_contents', $editor->id);
01771         $DB->update_record("lesson_pages", $editor);
01772 
01773         if ($newpage->prevpageid > 0) {
01774             $DB->set_field("lesson_pages", "nextpageid", $newpage->id, array("id" => $newpage->prevpageid));
01775         }
01776         if ($newpage->nextpageid > 0) {
01777             $DB->set_field("lesson_pages", "prevpageid", $newpage->id, array("id" => $newpage->nextpageid));
01778         }
01779 
01780         $page = lesson_page::load($newpage, $lesson);
01781         $page->create_answers($properties);
01782 
01783         $lesson->add_message(get_string('insertedpage', 'lesson').': '.format_string($newpage->title, true), 'notifysuccess');
01784 
01785         return $page;
01786     }
01787 
01798     final public static function load($id, lesson $lesson) {
01799         global $DB;
01800 
01801         if (is_object($id) && !empty($id->qtype)) {
01802             $page = $id;
01803         } else {
01804             $page = $DB->get_record("lesson_pages", array("id" => $id));
01805             if (!$page) {
01806                 print_error('cannotfindpages', 'lesson');
01807             }
01808         }
01809         $manager = lesson_page_type_manager::get($lesson);
01810 
01811         $class = 'lesson_page_type_'.$manager->get_page_type_idstring($page->qtype);
01812         if (!class_exists($class)) {
01813             $class = 'lesson_page';
01814         }
01815 
01816         return new $class($page, $lesson);
01817     }
01818 
01824     final public function delete() {
01825         global $DB;
01826         // first delete all the associated records...
01827         $DB->delete_records("lesson_attempts", array("pageid" => $this->properties->id));
01828         // ...now delete the answers...
01829         $DB->delete_records("lesson_answers", array("pageid" => $this->properties->id));
01830         // ..and the page itself
01831         $DB->delete_records("lesson_pages", array("id" => $this->properties->id));
01832 
01833         // repair the hole in the linkage
01834         if (!$this->properties->prevpageid && !$this->properties->nextpageid) {
01835             //This is the only page, no repair needed
01836         } elseif (!$this->properties->prevpageid) {
01837             // this is the first page...
01838             $page = $this->lesson->load_page($this->properties->nextpageid);
01839             $page->move(null, 0);
01840         } elseif (!$this->properties->nextpageid) {
01841             // this is the last page...
01842             $page = $this->lesson->load_page($this->properties->prevpageid);
01843             $page->move(0);
01844         } else {
01845             // page is in the middle...
01846             $prevpage = $this->lesson->load_page($this->properties->prevpageid);
01847             $nextpage = $this->lesson->load_page($this->properties->nextpageid);
01848 
01849             $prevpage->move($nextpage->id);
01850             $nextpage->move(null, $prevpage->id);
01851         }
01852         return true;
01853     }
01854 
01863     final public function move($nextpageid=null, $prevpageid=null) {
01864         global $DB;
01865         if ($nextpageid === null) {
01866             $nextpageid = $this->properties->nextpageid;
01867         }
01868         if ($prevpageid === null) {
01869             $prevpageid = $this->properties->prevpageid;
01870         }
01871         $obj = new stdClass;
01872         $obj->id = $this->properties->id;
01873         $obj->prevpageid = $prevpageid;
01874         $obj->nextpageid = $nextpageid;
01875         $DB->update_record('lesson_pages', $obj);
01876     }
01877 
01884     final public function get_answers() {
01885         global $DB;
01886         if ($this->answers === null) {
01887             $this->answers = array();
01888             $answers = $DB->get_records('lesson_answers', array('pageid'=>$this->properties->id, 'lessonid'=>$this->lesson->id), 'id');
01889             if (!$answers) {
01890                 // It is possible that a lesson upgraded from Moodle 1.9 still
01891                 // contains questions without any answers [MDL-25632].
01892                 // debugging(get_string('cannotfindanswer', 'lesson'));
01893                 return array();
01894             }
01895             foreach ($answers as $answer) {
01896                 $this->answers[count($this->answers)] = new lesson_page_answer($answer);
01897             }
01898         }
01899         return $this->answers;
01900     }
01901 
01907     final protected function get_lesson() {
01908         return $this->lesson;
01909     }
01910 
01916     final protected function get_type() {
01917         return $this->type;
01918     }
01919 
01928     final public function record_attempt($context) {
01929         global $DB, $USER, $OUTPUT;
01930 
01935         $result = $this->check_answer();
01936 
01937         $result->attemptsremaining  = 0;
01938         $result->maxattemptsreached = false;
01939 
01940         if ($result->noanswer) {
01941             $result->newpageid = $this->properties->id; // display same page again
01942             $result->feedback  = get_string('noanswer', 'lesson');
01943         } else {
01944             if (!has_capability('mod/lesson:manage', $context)) {
01945                 $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->lesson->id, "userid"=>$USER->id));
01946                 // record student's attempt
01947                 $attempt = new stdClass;
01948                 $attempt->lessonid = $this->lesson->id;
01949                 $attempt->pageid = $this->properties->id;
01950                 $attempt->userid = $USER->id;
01951                 $attempt->answerid = $result->answerid;
01952                 $attempt->retry = $nretakes;
01953                 $attempt->correct = $result->correctanswer;
01954                 if($result->userresponse !== null) {
01955                     $attempt->useranswer = $result->userresponse;
01956                 }
01957 
01958                 $attempt->timeseen = time();
01959                 // if allow modattempts, then update the old attempt record, otherwise, insert new answer record
01960                 if (isset($USER->modattempts[$this->lesson->id])) {
01961                     $attempt->retry = $nretakes - 1; // they are going through on review, $nretakes will be too high
01962                 }
01963 
01964                 if ($this->lesson->retake || (!$this->lesson->retake && $nretakes == 0)) {
01965                     $DB->insert_record("lesson_attempts", $attempt);
01966                 }
01967                 // "number of attempts remaining" message if $this->lesson->maxattempts > 1
01968                 // displaying of message(s) is at the end of page for more ergonomic display
01969                 if (!$result->correctanswer && ($result->newpageid == 0)) {
01970                     // wrong answer and student is stuck on this page - check how many attempts
01971                     // the student has had at this page/question
01972                     $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $attempt->retry));
01973                     // retreive the number of attempts left counter for displaying at bottom of feedback page
01974                     if ($nattempts >= $this->lesson->maxattempts) {
01975                         if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt
01976                             $result->maxattemptsreached = true;
01977                         }
01978                         $result->newpageid = LESSON_NEXTPAGE;
01979                     } else if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt
01980                         $result->attemptsremaining = $this->lesson->maxattempts - $nattempts;
01981                     }
01982                 }
01983             }
01984             // TODO: merge this code with the jump code below.  Convert jumpto page into a proper page id
01985             if ($result->newpageid == 0) {
01986                 $result->newpageid = $this->properties->id;
01987             } elseif ($result->newpageid == LESSON_NEXTPAGE) {
01988                 $result->newpageid = $this->lesson->get_next_page($this->properties->nextpageid);
01989             }
01990 
01991             // Determine default feedback if necessary
01992             if (empty($result->response)) {
01993                 if (!$this->lesson->feedback && !$result->noanswer && !($this->lesson->review & !$result->correctanswer && !$result->isessayquestion)) {
01994                     // These conditions have been met:
01995                     //  1. The lesson manager has not supplied feedback to the student
01996                     //  2. Not displaying default feedback
01997                     //  3. The user did provide an answer
01998                     //  4. We are not reviewing with an incorrect answer (and not reviewing an essay question)
01999 
02000                     $result->nodefaultresponse = true;  // This will cause a redirect below
02001                 } else if ($result->isessayquestion) {
02002                     $result->response = get_string('defaultessayresponse', 'lesson');
02003                 } else if ($result->correctanswer) {
02004                     $result->response = get_string('thatsthecorrectanswer', 'lesson');
02005                 } else {
02006                     $result->response = get_string('thatsthewronganswer', 'lesson');
02007                 }
02008             }
02009 
02010             if ($result->response) {
02011                 if ($this->lesson->review && !$result->correctanswer && !$result->isessayquestion) {
02012                     $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$this->lesson->id, "userid"=>$USER->id));
02013                     $qattempts = $DB->count_records("lesson_attempts", array("userid"=>$USER->id, "retry"=>$nretakes, "pageid"=>$this->properties->id));
02014                     if ($qattempts == 1) {
02015                         $result->feedback = $OUTPUT->box(get_string("firstwrong", "lesson"), 'feedback');
02016                     } else {
02017                         $result->feedback = $OUTPUT->BOX(get_string("secondpluswrong", "lesson"), 'feedback');
02018                     }
02019                 } else {
02020                     $class = 'response';
02021                     if ($result->correctanswer) {
02022                         $class .= ' correct'; //CSS over-ride this if they exist (!important)
02023                     } else if (!$result->isessayquestion) {
02024                         $class .= ' incorrect'; //CSS over-ride this if they exist (!important)
02025                     }
02026                     $options = new stdClass;
02027                     $options->noclean = true;
02028                     $options->para = true;
02029                     $options->overflowdiv = true;
02030                     $result->feedback = $OUTPUT->box(format_text($this->get_contents(), $this->properties->contentsformat, $options), 'generalbox boxaligncenter');
02031                     $result->feedback .= '<div class="correctanswer generalbox"><em>'.get_string("youranswer", "lesson").'</em> : '.$result->studentanswer; // already in clean html
02032                     $result->feedback .= $OUTPUT->box($result->response, $class); // already conerted to HTML
02033                     $result->feedback .= '</div>';
02034                 }
02035             }
02036         }
02037 
02038         return $result;
02039     }
02040 
02048     final protected function get_jump_name($jumpto) {
02049         global $DB;
02050         static $jumpnames = array();
02051 
02052         if (!array_key_exists($jumpto, $jumpnames)) {
02053             if ($jumpto == LESSON_THISPAGE) {
02054                 $jumptitle = get_string('thispage', 'lesson');
02055             } elseif ($jumpto == LESSON_NEXTPAGE) {
02056                 $jumptitle = get_string('nextpage', 'lesson');
02057             } elseif ($jumpto == LESSON_EOL) {
02058                 $jumptitle = get_string('endoflesson', 'lesson');
02059             } elseif ($jumpto == LESSON_UNSEENBRANCHPAGE) {
02060                 $jumptitle = get_string('unseenpageinbranch', 'lesson');
02061             } elseif ($jumpto == LESSON_PREVIOUSPAGE) {
02062                 $jumptitle = get_string('previouspage', 'lesson');
02063             } elseif ($jumpto == LESSON_RANDOMPAGE) {
02064                 $jumptitle = get_string('randompageinbranch', 'lesson');
02065             } elseif ($jumpto == LESSON_RANDOMBRANCH) {
02066                 $jumptitle = get_string('randombranch', 'lesson');
02067             } elseif ($jumpto == LESSON_CLUSTERJUMP) {
02068                 $jumptitle = get_string('clusterjump', 'lesson');
02069             } else {
02070                 if (!$jumptitle = $DB->get_field('lesson_pages', 'title', array('id' => $jumpto))) {
02071                     $jumptitle = '<strong>'.get_string('notdefined', 'lesson').'</strong>';
02072                 }
02073             }
02074             $jumpnames[$jumpto] = format_string($jumptitle,true);
02075         }
02076 
02077         return $jumpnames[$jumpto];
02078     }
02079 
02085     public function __construct($properties, lesson $lesson) {
02086         parent::__construct($properties);
02087         $this->lesson = $lesson;
02088     }
02089 
02097     public function earned_score($answers, $attempt) {
02098         return $answers[$attempt->answerid]->score;
02099     }
02100 
02108     public function callback_on_view($canmanage) {
02109         return true;
02110     }
02111 
02118     public function update($properties, $context = null, $maxbytes = null) {
02119         global $DB, $PAGE;
02120         $answers  = $this->get_answers();
02121         $properties->id = $this->properties->id;
02122         $properties->lessonid = $this->lesson->id;
02123         if (empty($properties->qoption)) {
02124             $properties->qoption = '0';
02125         }
02126         if (empty($context)) {
02127             $context = $PAGE->context;
02128         }
02129         if ($maxbytes === null) {
02130             $maxbytes =get_max_upload_file_size();
02131         }
02132         $properties = file_postupdate_standard_editor($properties, 'contents', array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$maxbytes), $context, 'mod_lesson', 'page_contents', $properties->id);
02133         $DB->update_record("lesson_pages", $properties);
02134 
02135         for ($i = 0; $i < $this->lesson->maxanswers; $i++) {
02136             if (!array_key_exists($i, $this->answers)) {
02137                 $this->answers[$i] = new stdClass;
02138                 $this->answers[$i]->lessonid = $this->lesson->id;
02139                 $this->answers[$i]->pageid = $this->id;
02140                 $this->answers[$i]->timecreated = $this->timecreated;
02141             }
02142 
02143             if (!empty($properties->answer_editor[$i]) && is_array($properties->answer_editor[$i])) {
02144                 $this->answers[$i]->answer = $properties->answer_editor[$i]['text'];
02145                 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format'];
02146             }
02147             if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
02148                 $this->answers[$i]->response = $properties->response_editor[$i]['text'];
02149                 $this->answers[$i]->responseformat = $properties->response_editor[$i]['format'];
02150             }
02151 
02152             // we don't need to check for isset here because properties called it's own isset method.
02153             if ($this->answers[$i]->answer != '') {
02154                 if (isset($properties->jumpto[$i])) {
02155                     $this->answers[$i]->jumpto = $properties->jumpto[$i];
02156                 }
02157                 if ($this->lesson->custom && isset($properties->score[$i])) {
02158                     $this->answers[$i]->score = $properties->score[$i];
02159                 }
02160                 if (!isset($this->answers[$i]->id)) {
02161                     $this->answers[$i]->id =  $DB->insert_record("lesson_answers", $this->answers[$i]);
02162                 } else {
02163                     $DB->update_record("lesson_answers", $this->answers[$i]->properties());
02164                 }
02165 
02166             } else if (isset($this->answers[$i]->id)) {
02167                 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id));
02168                 unset($this->answers[$i]);
02169             }
02170         }
02171         return true;
02172     }
02173 
02180     public function add_page_link($previd) {
02181         return false;
02182     }
02183 
02191     public function is_unseen($param) {
02192         global $USER, $DB;
02193         if (is_array($param)) {
02194             $seenpages = $param;
02195             return (!array_key_exists($this->properties->id, $seenpages));
02196         } else {
02197             $nretakes = $param;
02198             if (!$DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry"=>$nretakes))) {
02199                 return true;
02200             }
02201         }
02202         return false;
02203     }
02204 
02210     public function is_unanswered($nretakes) {
02211         global $DB, $USER;
02212         if (!$DB->count_records("lesson_attempts", array('pageid'=>$this->properties->id, 'userid'=>$USER->id, 'correct'=>1, 'retry'=>$nretakes))) {
02213             return true;
02214         }
02215         return false;
02216     }
02217 
02224     public function create_answers($properties) {
02225         global $DB;
02226         // now add the answers
02227         $newanswer = new stdClass;
02228         $newanswer->lessonid = $this->lesson->id;
02229         $newanswer->pageid = $this->properties->id;
02230         $newanswer->timecreated = $this->properties->timecreated;
02231 
02232         $answers = array();
02233 
02234         for ($i = 0; $i < $this->lesson->maxanswers; $i++) {
02235             $answer = clone($newanswer);
02236 
02237             if (!empty($properties->answer_editor[$i]) && is_array($properties->answer_editor[$i])) {
02238                 $answer->answer = $properties->answer_editor[$i]['text'];
02239                 $answer->answerformat = $properties->answer_editor[$i]['format'];
02240             }
02241             if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
02242                 $answer->response = $properties->response_editor[$i]['text'];
02243                 $answer->responseformat = $properties->response_editor[$i]['format'];
02244             }
02245 
02246             if (isset($answer->answer) && $answer->answer != '') {
02247                 if (isset($properties->jumpto[$i])) {
02248                     $answer->jumpto = $properties->jumpto[$i];
02249                 }
02250                 if ($this->lesson->custom && isset($properties->score[$i])) {
02251                     $answer->score = $properties->score[$i];
02252                 }
02253                 $answer->id = $DB->insert_record("lesson_answers", $answer);
02254                 $answers[$answer->id] = new lesson_page_answer($answer);
02255             } else {
02256                 break;
02257             }
02258         }
02259 
02260         $this->answers = $answers;
02261         return $answers;
02262     }
02263 
02277     public function check_answer() {
02278         $result = new stdClass;
02279         $result->answerid        = 0;
02280         $result->noanswer        = false;
02281         $result->correctanswer   = false;
02282         $result->isessayquestion = false;   // use this to turn off review button on essay questions
02283         $result->response        = '';
02284         $result->newpageid       = 0;       // stay on the page
02285         $result->studentanswer   = '';      // use this to store student's answer(s) in order to display it on feedback page
02286         $result->userresponse    = null;
02287         $result->feedback        = '';
02288         $result->nodefaultresponse  = false; // Flag for redirecting when default feedback is turned off
02289         return $result;
02290     }
02291 
02299     public function has_option() {
02300         return false;
02301     }
02302 
02310     public function max_answers($default) {
02311         return $default;
02312     }
02313 
02318     public function properties() {
02319         $properties = clone($this->properties);
02320         if ($this->answers === null) {
02321             $this->get_answers();
02322         }
02323         if (count($this->answers)>0) {
02324             $count = 0;
02325             foreach ($this->answers as $answer) {
02326                 $properties->{'answer_editor['.$count.']'} = array('text'=>$answer->answer, 'format'=>$answer->answerformat);
02327                 $properties->{'response_editor['.$count.']'} = array('text'=>$answer->response, 'format'=>$answer->responseformat);
02328                 $properties->{'jumpto['.$count.']'} = $answer->jumpto;
02329                 $properties->{'score['.$count.']'} = $answer->score;
02330                 $count++;
02331             }
02332         }
02333         return $properties;
02334     }
02335 
02343     public static function get_jumptooptions($pageid, lesson $lesson) {
02344         global $DB;
02345         $jump = array();
02346         $jump[0] = get_string("thispage", "lesson");
02347         $jump[LESSON_NEXTPAGE] = get_string("nextpage", "lesson");
02348         $jump[LESSON_PREVIOUSPAGE] = get_string("previouspage", "lesson");
02349         $jump[LESSON_EOL] = get_string("endoflesson", "lesson");
02350 
02351         if ($pageid == 0) {
02352             return $jump;
02353         }
02354 
02355         $pages = $lesson->load_all_pages();
02356         if ($pages[$pageid]->qtype == LESSON_PAGE_BRANCHTABLE || $lesson->is_sub_page_of_type($pageid, array(LESSON_PAGE_BRANCHTABLE), array(LESSON_PAGE_ENDOFBRANCH, LESSON_PAGE_CLUSTER))) {
02357             $jump[LESSON_UNSEENBRANCHPAGE] = get_string("unseenpageinbranch", "lesson");
02358             $jump[LESSON_RANDOMPAGE] = get_string("randompageinbranch", "lesson");
02359         }
02360         if($pages[$pageid]->qtype == LESSON_PAGE_CLUSTER || $lesson->is_sub_page_of_type($pageid, array(LESSON_PAGE_CLUSTER), array(LESSON_PAGE_ENDOFCLUSTER))) {
02361             $jump[LESSON_CLUSTERJUMP] = get_string("clusterjump", "lesson");
02362         }
02363         if (!optional_param('firstpage', 0, PARAM_INT)) {
02364             $apageid = $DB->get_field("lesson_pages", "id", array("lessonid" => $lesson->id, "prevpageid" => 0));
02365             while (true) {
02366                 if ($apageid) {
02367                     $title = $DB->get_field("lesson_pages", "title", array("id" => $apageid));
02368                     $jump[$apageid] = strip_tags(format_string($title,true));
02369                     $apageid = $DB->get_field("lesson_pages", "nextpageid", array("id" => $apageid));
02370                 } else {
02371                     // last page reached
02372                     break;
02373                 }
02374             }
02375         }
02376         return $jump;
02377     }
02383     public function get_contents() {
02384         global $PAGE;
02385         if (!empty($this->properties->contents)) {
02386             if (!isset($this->properties->contentsformat)) {
02387                 $this->properties->contentsformat = FORMAT_HTML;
02388             }
02389             $context = get_context_instance(CONTEXT_MODULE, $PAGE->cm->id);
02390             $contents = file_rewrite_pluginfile_urls($this->properties->contents, 'pluginfile.php', $context->id, 'mod_lesson', 'page_contents', $this->properties->id); // must do this BEFORE format_text()!!!!!!
02391             return format_text($contents, $this->properties->contentsformat, array('context'=>$context, 'noclean'=>true)); // page edit is marked with XSS, we want all content here
02392         } else {
02393             return '';
02394         }
02395     }
02396 
02401     protected function get_displayinmenublock() {
02402         return false;
02403     }
02404 
02409     public function option_description_string() {
02410         return '';
02411     }
02412 
02418     public function display_answers(html_table $table) {
02419         $answers = $this->get_answers();
02420         $i = 1;
02421         foreach ($answers as $answer) {
02422             $cells = array();
02423             $cells[] = "<span class=\"label\">".get_string("jump", "lesson")." $i<span>: ";
02424             $cells[] = $this->get_jump_name($answer->jumpto);
02425             $table->data[] = new html_table_row($cells);
02426             if ($i === 1){
02427                 $table->data[count($table->data)-1]->cells[0]->style = 'width:20%;';
02428             }
02429             $i++;
02430         }
02431         return $table;
02432     }
02433 
02438     protected function get_grayout() {
02439         return 0;
02440     }
02441 
02449     public function stats(array &$pagestats, $tries) {
02450         return true;
02451     }
02452 
02464     public function report_answers($answerpage, $answerdata, $useranswer, $pagestats, &$i, &$n) {
02465         $answers = $this->get_answers();
02466         $formattextdefoptions = new stdClass;
02467         $formattextdefoptions->para = false;  //I'll use it widely in this page
02468         foreach ($answers as $answer) {
02469             $data = get_string('jumpsto', 'lesson', $this->get_jump_name($answer->jumpto));
02470             $answerdata->answers[] = array($data, "");
02471             $answerpage->answerdata = $answerdata;
02472         }
02473         return $answerpage;
02474     }
02475 
02481     public function get_jumps() {
02482         global $DB;
02483         $jumps = array();
02484         $params = array ("lessonid" => $this->lesson->id, "pageid" => $this->properties->id);
02485         if ($answers = $this->get_answers()) {
02486             foreach ($answers as $answer) {
02487                 $jumps[] = $this->get_jump_name($answer->jumpto);
02488             }
02489         } else {
02490             $jumps[] = $this->get_jump_name($this->properties->nextpageid);
02491         }
02492         return $jumps;
02493     }
02498     public function requires_manual_grading() {
02499         return false;
02500     }
02501 
02507     public function override_next_page() {
02508         return false;
02509     }
02510 
02518     public function valid_page_and_view(&$validpages, &$pageviews) {
02519         $validpages[$this->properties->id] = 1;
02520         return $this->properties->nextpageid;
02521     }
02522 }
02523 
02524 
02525 
02544 class lesson_page_answer extends lesson_base {
02545 
02552     public static function load($id) {
02553         global $DB;
02554         $answer = $DB->get_record("lesson_answers", array("id" => $id));
02555         return new lesson_page_answer($answer);
02556     }
02557 
02566     public static function create($properties, lesson_page $page) {
02567         return $page->create_answers($properties);
02568     }
02569 
02570 }
02571 
02586 class lesson_page_type_manager {
02587 
02592     protected $types = array();
02593 
02603     public static function get(lesson $lesson) {
02604         static $pagetypemanager;
02605         if (!($pagetypemanager instanceof lesson_page_type_manager)) {
02606             $pagetypemanager = new lesson_page_type_manager();
02607             $pagetypemanager->load_lesson_types($lesson);
02608         }
02609         return $pagetypemanager;
02610     }
02611 
02617     public function load_lesson_types(lesson $lesson) {
02618         global $CFG;
02619         $basedir = $CFG->dirroot.'/mod/lesson/pagetypes/';
02620         $dir = dir($basedir);
02621         while (false !== ($entry = $dir->read())) {
02622             if (strpos($entry, '.')===0 || !preg_match('#^[a-zA-Z]+\.php#i', $entry)) {
02623                 continue;
02624             }
02625             require_once($basedir.$entry);
02626             $class = 'lesson_page_type_'.strtok($entry,'.');
02627             if (class_exists($class)) {
02628                 $pagetype = new $class(new stdClass, $lesson);
02629                 $this->types[$pagetype->typeid] = $pagetype;
02630             }
02631         }
02632 
02633     }
02634 
02641     public function get_page_type_strings($type=null, $special=true) {
02642         $types = array();
02643         foreach ($this->types as $pagetype) {
02644             if (($type===null || $pagetype->type===$type) && ($special===true || $pagetype->is_standard())) {
02645                 $types[$pagetype->typeid] = $pagetype->typestring;
02646             }
02647         }
02648         return $types;
02649     }
02650 
02660     public function get_page_type_idstring($id) {
02661         foreach ($this->types as $pagetype) {
02662             if ((int)$pagetype->typeid === (int)$id) {
02663                 return $pagetype->idstring;
02664             }
02665         }
02666         return 'unknown';
02667     }
02668 
02680     public function load_page($pageid, lesson $lesson) {
02681         global $DB;
02682         if (!($page =$DB->get_record('lesson_pages', array('id'=>$pageid, 'lessonid'=>$lesson->id)))) {
02683             print_error('cannotfindpages', 'lesson');
02684         }
02685         $pagetype = get_class($this->types[$page->qtype]);
02686         $page = new $pagetype($page, $lesson);
02687         return $page;
02688     }
02689 
02696     public function load_all_pages(lesson $lesson) {
02697         global $DB;
02698         if (!($pages =$DB->get_records('lesson_pages', array('lessonid'=>$lesson->id)))) {
02699             print_error('cannotfindpages', 'lesson');
02700         }
02701         foreach ($pages as $key=>$page) {
02702             $pagetype = get_class($this->types[$page->qtype]);
02703             $pages[$key] = new $pagetype($page, $lesson);
02704         }
02705 
02706         $orderedpages = array();
02707         $lastpageid = 0;
02708 
02709         while (true) {
02710             foreach ($pages as $page) {
02711                 if ((int)$page->prevpageid === (int)$lastpageid) {
02712                     $orderedpages[$page->id] = $page;
02713                     unset($pages[$page->id]);
02714                     $lastpageid = $page->id;
02715                     if ((int)$page->nextpageid===0) {
02716                         break 2;
02717                     } else {
02718                         break 1;
02719                     }
02720                 }
02721             }
02722         }
02723 
02724         return $orderedpages;
02725     }
02726 
02734     public function get_page_form($type, $arguments) {
02735         $class = 'lesson_add_page_form_'.$this->get_page_type_idstring($type);
02736         if (!class_exists($class) || get_parent_class($class)!=='lesson_add_page_form_base') {
02737             debugging('Lesson page type unknown class requested '.$class, DEBUG_DEVELOPER);
02738             $class = 'lesson_add_page_form_selection';
02739         } else if ($class === 'lesson_add_page_form_unknown') {
02740             $class = 'lesson_add_page_form_selection';
02741         }
02742         return new $class(null, $arguments);
02743     }
02744 
02750     public function get_add_page_type_links($previd) {
02751         global $OUTPUT;
02752 
02753         $links = array();
02754 
02755         foreach ($this->types as $key=>$type) {
02756             if ($link = $type->add_page_link($previd)) {
02757                 $links[$key] = $link;
02758             }
02759         }
02760 
02761         return $links;
02762     }
02763 }
 All Data Structures Namespaces Files Functions Variables Enumerations