From 945a81a943556fb353309fa6179215ea6fa602d3 Mon Sep 17 00:00:00 2001 From: Michael Aherne Date: Fri, 6 Jul 2012 15:14:10 +0100 Subject: [PATCH 001/106] MDL-34205 Activity chooser default setting --- admin/settings/appearance.php | 1 + course/lib.php | 2 +- lang/en/admin.php | 2 ++ lib/navigationlib.php | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/admin/settings/appearance.php b/admin/settings/appearance.php index b0272b8c97e..9995af38048 100644 --- a/admin/settings/appearance.php +++ b/admin/settings/appearance.php @@ -185,6 +185,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page $setting = new admin_setting_configcheckbox('cachejs', new lang_string('cachejs', 'admin'), new lang_string('cachejs_help', 'admin'), 1); $setting->set_updatedcallback('js_reset_all_caches'); $temp->add($setting); + $temp->add(new admin_setting_configcheckbox('modchooserdefault', new lang_string('modchooserdefault', 'admin'), new lang_string('configmodchooserdefault', 'admin'), 1)); $ADMIN->add('appearance', $temp); // link to tag management interface diff --git a/course/lib.php b/course/lib.php index 374b309c775..a64edde1a46 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1863,7 +1863,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false, $modchooser.= html_writer::end_tag('div'); // Wrap the normal output in a noscript div - $usemodchooser = get_user_preferences('usemodchooser', 1); + $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault); if ($usemodchooser) { $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown')); $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser')); diff --git a/lang/en/admin.php b/lang/en/admin.php index baf70f5ba73..720e799ee64 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -253,6 +253,7 @@ $string['configminpasswordlength'] = 'Passwords must be at least these many char $string['configminpasswordlower'] = 'Passwords must have at least these many lower case letters.'; $string['configminpasswordnonalphanum'] = 'Passwords must have at least these many non-alphanumeric characters.'; $string['configminpasswordupper'] = 'Passwords must have at least these many upper case letters.'; +$string['configmodchooserdefault'] = 'Should the activity chooser be presented to users by default?'; $string['configmycoursesperpage'] = 'Maximum number of courses to display in any list of a user\'s own courses'; $string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my'; $string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins'; @@ -679,6 +680,7 @@ $string['mnetrestore_extusers_admin'] = 'Note: This backup file $string['mnetrestore_extusers_mismatch'] = 'Note: This backup file apparently originates from a different Moodle installation and contains remote Moodle Network user accounts that may fail to restore. This operation is unsupported. If you are certain that it was created on this Moodle installation, or you can ensure that all the needed Moodle Network Hosts are configured, you may want to still try the restore.'; $string['mnetrestore_extusers_noadmin'] = 'Note: This backup file seems to come from a different Moodle installation and contains remote Moodle Network user accounts. You are not allowed to execute this type of restore. Contact the administrator of the site or, alternatively, restore this course without any user information (modules, files...)'; $string['mnetrestore_extusers_switchuserauth'] = 'Remote Moodle Network user {$a->username} (coming from {$a->mnethosturl}) switched to local {$a->auth} authenticated user.'; +$string['modchooserdefault'] = 'Activity chooser default'; $string['modeditdefaults'] = 'Default values for activity settings'; $string['modsettings'] = 'Manage activities'; $string['modulesecurity'] = 'Module security'; diff --git a/lib/navigationlib.php b/lib/navigationlib.php index 82b3ad97723..92f90297adb 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -3573,7 +3573,7 @@ class settings_navigation extends navigation_node { // Add the module chooser toggle $modchoosertoggleurl = clone($baseurl); if ($this->page->user_is_editing() && course_ajax_enabled($course)) { - if ($usemodchooser = get_user_preferences('usemodchooser', 1)) { + if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) { $modchoosertogglestring = get_string('modchooserdisable', 'moodle'); $modchoosertoggleurl->param('modchooser', 'off'); } else { From 7534234322c9646f5f8770721fb82c3403f1de6c Mon Sep 17 00:00:00 2001 From: Aparup Banerjee Date: Mon, 9 Jul 2012 20:57:09 +0800 Subject: [PATCH 002/106] MDL-34225 course completion : move /lib/completion/* up to /completion --- .../completion_aggregation.php | 2 +- .../completion_completion.php | 2 +- .../completion_criteria.php | 6 +++--- .../completion_criteria_activity.php | 0 .../completion_criteria_completion.php | 2 +- .../completion_criteria_course.php | 0 .../completion_criteria_date.php | 0 .../completion_criteria_duration.php | 0 .../completion_criteria_grade.php | 0 .../completion_criteria_role.php | 0 .../completion_criteria_self.php | 0 .../completion_criteria_unenrol.php | 0 {lib/completion => completion}/cron.php | 2 +- {lib/completion => completion}/data_object.php | 0 course/completion.php | 16 ++++++++-------- lib/completionlib.php | 8 ++++---- lib/cronlib.php | 2 +- lib/db/upgrade.php | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) rename {lib/completion => completion}/completion_aggregation.php (98%) rename {lib/completion => completion}/completion_completion.php (98%) rename {lib/completion => completion}/completion_criteria.php (97%) rename {lib/completion => completion}/completion_criteria_activity.php (100%) rename {lib/completion => completion}/completion_criteria_completion.php (98%) rename {lib/completion => completion}/completion_criteria_course.php (100%) rename {lib/completion => completion}/completion_criteria_date.php (100%) rename {lib/completion => completion}/completion_criteria_duration.php (100%) rename {lib/completion => completion}/completion_criteria_grade.php (100%) rename {lib/completion => completion}/completion_criteria_role.php (100%) rename {lib/completion => completion}/completion_criteria_self.php (100%) rename {lib/completion => completion}/completion_criteria_unenrol.php (100%) rename {lib/completion => completion}/cron.php (99%) rename {lib/completion => completion}/data_object.php (100%) diff --git a/lib/completion/completion_aggregation.php b/completion/completion_aggregation.php similarity index 98% rename from lib/completion/completion_aggregation.php rename to completion/completion_aggregation.php index e6e626a4de9..0c4d4575505 100644 --- a/lib/completion/completion_aggregation.php +++ b/completion/completion_aggregation.php @@ -26,7 +26,7 @@ */ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/completion/data_object.php'); +require_once($CFG->dirroot.'/completion/data_object.php'); /** * Course completion critieria aggregation diff --git a/lib/completion/completion_completion.php b/completion/completion_completion.php similarity index 98% rename from lib/completion/completion_completion.php rename to completion/completion_completion.php index e6523eadf26..a250b194cdf 100644 --- a/lib/completion/completion_completion.php +++ b/completion/completion_completion.php @@ -25,7 +25,7 @@ */ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/completion/data_object.php'); +require_once($CFG->dirroot.'/completion/data_object.php'); /** * Course completion status for a particular user/course diff --git a/lib/completion/completion_criteria.php b/completion/completion_criteria.php similarity index 97% rename from lib/completion/completion_criteria.php rename to completion/completion_criteria.php index 31f5187edcb..d597b44decb 100644 --- a/lib/completion/completion_criteria.php +++ b/completion/completion_criteria.php @@ -25,8 +25,8 @@ */ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/completion/data_object.php'); -require_once($CFG->libdir.'/completion/completion_criteria_completion.php'); +require_once($CFG->dirroot.'/completion/data_object.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_completion.php'); /** * Self completion criteria type @@ -172,7 +172,7 @@ abstract class completion_criteria extends data_object { } $class = 'completion_criteria_'.$COMPLETION_CRITERIA_TYPES[$params['criteriatype']]; - require_once($CFG->libdir.'/completion/'.$class.'.php'); + require_once($CFG->dirroot.'/completion/'.$class.'.php'); return new $class($params, false); } diff --git a/lib/completion/completion_criteria_activity.php b/completion/completion_criteria_activity.php similarity index 100% rename from lib/completion/completion_criteria_activity.php rename to completion/completion_criteria_activity.php diff --git a/lib/completion/completion_criteria_completion.php b/completion/completion_criteria_completion.php similarity index 98% rename from lib/completion/completion_criteria_completion.php rename to completion/completion_criteria_completion.php index 7f448001d20..48496964c94 100644 --- a/lib/completion/completion_criteria_completion.php +++ b/completion/completion_criteria_completion.php @@ -25,7 +25,7 @@ */ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/completion/data_object.php'); +require_once($CFG->dirroot.'/completion/data_object.php'); /** * Completion data for a specific user, course and critieria diff --git a/lib/completion/completion_criteria_course.php b/completion/completion_criteria_course.php similarity index 100% rename from lib/completion/completion_criteria_course.php rename to completion/completion_criteria_course.php diff --git a/lib/completion/completion_criteria_date.php b/completion/completion_criteria_date.php similarity index 100% rename from lib/completion/completion_criteria_date.php rename to completion/completion_criteria_date.php diff --git a/lib/completion/completion_criteria_duration.php b/completion/completion_criteria_duration.php similarity index 100% rename from lib/completion/completion_criteria_duration.php rename to completion/completion_criteria_duration.php diff --git a/lib/completion/completion_criteria_grade.php b/completion/completion_criteria_grade.php similarity index 100% rename from lib/completion/completion_criteria_grade.php rename to completion/completion_criteria_grade.php diff --git a/lib/completion/completion_criteria_role.php b/completion/completion_criteria_role.php similarity index 100% rename from lib/completion/completion_criteria_role.php rename to completion/completion_criteria_role.php diff --git a/lib/completion/completion_criteria_self.php b/completion/completion_criteria_self.php similarity index 100% rename from lib/completion/completion_criteria_self.php rename to completion/completion_criteria_self.php diff --git a/lib/completion/completion_criteria_unenrol.php b/completion/completion_criteria_unenrol.php similarity index 100% rename from lib/completion/completion_criteria_unenrol.php rename to completion/completion_criteria_unenrol.php diff --git a/lib/completion/cron.php b/completion/cron.php similarity index 99% rename from lib/completion/cron.php rename to completion/cron.php index 3645c0618d6..038577935bd 100644 --- a/lib/completion/cron.php +++ b/completion/cron.php @@ -207,7 +207,7 @@ function completion_cron_criteria() { foreach ($COMPLETION_CRITERIA_TYPES as $type) { $object = 'completion_criteria_'.$type; - require_once $CFG->libdir.'/completion/'.$object.'.php'; + require_once 'completion/'.$object.'.php'; $class = new $object(); diff --git a/lib/completion/data_object.php b/completion/data_object.php similarity index 100% rename from lib/completion/data_object.php rename to completion/data_object.php diff --git a/course/completion.php b/course/completion.php index a25c2af30f9..2a4d77a458f 100644 --- a/course/completion.php +++ b/course/completion.php @@ -28,14 +28,14 @@ require_once('../config.php'); require_once('lib.php'); require_once($CFG->libdir.'/completionlib.php'); -require_once($CFG->libdir.'/completion/completion_criteria_self.php'); -require_once($CFG->libdir.'/completion/completion_criteria_date.php'); -require_once($CFG->libdir.'/completion/completion_criteria_unenrol.php'); -require_once($CFG->libdir.'/completion/completion_criteria_activity.php'); -require_once($CFG->libdir.'/completion/completion_criteria_duration.php'); -require_once($CFG->libdir.'/completion/completion_criteria_grade.php'); -require_once($CFG->libdir.'/completion/completion_criteria_role.php'); -require_once($CFG->libdir.'/completion/completion_criteria_course.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_self.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_date.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_unenrol.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_activity.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_duration.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_grade.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_role.php'); +require_once($CFG->dirroot.'/completion/completion_criteria_course.php'); require_once $CFG->libdir.'/gradelib.php'; require_once('completion_form.php'); diff --git a/lib/completionlib.php b/lib/completionlib.php index 4df3bc0cc8c..c26e49acaa9 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -31,10 +31,10 @@ defined('MOODLE_INTERNAL') || die(); /** * Include the required completion libraries */ -require_once $CFG->libdir.'/completion/completion_aggregation.php'; -require_once $CFG->libdir.'/completion/completion_criteria.php'; -require_once $CFG->libdir.'/completion/completion_completion.php'; -require_once $CFG->libdir.'/completion/completion_criteria_completion.php'; +require_once $CFG->dirroot.'/completion/completion_aggregation.php'; +require_once $CFG->dirroot.'/completion/completion_criteria.php'; +require_once $CFG->dirroot.'/completion/completion_completion.php'; +require_once $CFG->dirroot.'/completion/completion_criteria_completion.php'; /** diff --git a/lib/cronlib.php b/lib/cronlib.php index b0347606e13..e4d18f30bf8 100644 --- a/lib/cronlib.php +++ b/lib/cronlib.php @@ -318,7 +318,7 @@ function cron_run() { if ($CFG->enablecompletion) { // Completion cron mtrace('Starting the completion cron...'); - require_once($CFG->libdir . '/completion/cron.php'); + require_once($CFG->dirroot.'/completion/cron.php'); completion_cron(); mtrace('done'); } diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index dd52946a463..42d99027be8 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -405,7 +405,7 @@ function xmldb_main_upgrade($oldversion) { } if ($oldversion < 2012042300.02) { - require_once($CFG->libdir . '/completion/completion_criteria.php'); + require_once($CFG->dirroot.'/completion/completion_criteria.php'); // Delete orphaned criteria which were left when modules were removed if ($DB->get_dbfamily() === 'mysql') { $sql = "DELETE cc FROM {course_completion_criteria} cc From 9710fe73d1796039de7a49ed9e97deaf04985dca Mon Sep 17 00:00:00 2001 From: Aaron Barnes Date: Tue, 10 Jul 2012 21:05:41 +1200 Subject: [PATCH 003/106] MDL-34243 completion: get_criteria() incorrectly passing object --- lib/completion/completion_criteria_completion.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/completion/completion_criteria_completion.php b/lib/completion/completion_criteria_completion.php index 7f448001d20..dabe5529e42 100644 --- a/lib/completion/completion_criteria_completion.php +++ b/lib/completion/completion_criteria_completion.php @@ -153,7 +153,7 @@ class completion_criteria_completion extends data_object { $record = $DB->get_record('course_completion_criteria', $params); - $this->attach_criteria(completion_criteria::factory($record)); + $this->attach_criteria(completion_criteria::factory((array) $record)); } return $this->_criteria; From 60829d80944616c9babf0625e8b0cd08ae6dde17 Mon Sep 17 00:00:00 2001 From: Aparup Banerjee Date: Tue, 10 Jul 2012 11:21:55 +0800 Subject: [PATCH 004/106] MDL-34225 course completion : moved criteria classes into criteria subdir --- .../{ => criteria}/completion_criteria.php | 2 +- .../completion_criteria_activity.php | 0 .../completion_criteria_course.php | 0 .../{ => criteria}/completion_criteria_date.php | 0 .../completion_criteria_duration.php | 0 .../{ => criteria}/completion_criteria_grade.php | 0 .../{ => criteria}/completion_criteria_role.php | 0 .../{ => criteria}/completion_criteria_self.php | 0 .../completion_criteria_unenrol.php | 0 completion/cron.php | 2 +- course/completion.php | 16 ++++++++-------- lib/completionlib.php | 2 +- lib/db/upgrade.php | 2 +- 13 files changed, 12 insertions(+), 12 deletions(-) rename completion/{ => criteria}/completion_criteria.php (99%) rename completion/{ => criteria}/completion_criteria_activity.php (100%) rename completion/{ => criteria}/completion_criteria_course.php (100%) rename completion/{ => criteria}/completion_criteria_date.php (100%) rename completion/{ => criteria}/completion_criteria_duration.php (100%) rename completion/{ => criteria}/completion_criteria_grade.php (100%) rename completion/{ => criteria}/completion_criteria_role.php (100%) rename completion/{ => criteria}/completion_criteria_self.php (100%) rename completion/{ => criteria}/completion_criteria_unenrol.php (100%) diff --git a/completion/completion_criteria.php b/completion/criteria/completion_criteria.php similarity index 99% rename from completion/completion_criteria.php rename to completion/criteria/completion_criteria.php index d597b44decb..a87abd3d676 100644 --- a/completion/completion_criteria.php +++ b/completion/criteria/completion_criteria.php @@ -172,7 +172,7 @@ abstract class completion_criteria extends data_object { } $class = 'completion_criteria_'.$COMPLETION_CRITERIA_TYPES[$params['criteriatype']]; - require_once($CFG->dirroot.'/completion/'.$class.'.php'); + require_once($CFG->dirroot.'/completion/criteria/'.$class.'.php'); return new $class($params, false); } diff --git a/completion/completion_criteria_activity.php b/completion/criteria/completion_criteria_activity.php similarity index 100% rename from completion/completion_criteria_activity.php rename to completion/criteria/completion_criteria_activity.php diff --git a/completion/completion_criteria_course.php b/completion/criteria/completion_criteria_course.php similarity index 100% rename from completion/completion_criteria_course.php rename to completion/criteria/completion_criteria_course.php diff --git a/completion/completion_criteria_date.php b/completion/criteria/completion_criteria_date.php similarity index 100% rename from completion/completion_criteria_date.php rename to completion/criteria/completion_criteria_date.php diff --git a/completion/completion_criteria_duration.php b/completion/criteria/completion_criteria_duration.php similarity index 100% rename from completion/completion_criteria_duration.php rename to completion/criteria/completion_criteria_duration.php diff --git a/completion/completion_criteria_grade.php b/completion/criteria/completion_criteria_grade.php similarity index 100% rename from completion/completion_criteria_grade.php rename to completion/criteria/completion_criteria_grade.php diff --git a/completion/completion_criteria_role.php b/completion/criteria/completion_criteria_role.php similarity index 100% rename from completion/completion_criteria_role.php rename to completion/criteria/completion_criteria_role.php diff --git a/completion/completion_criteria_self.php b/completion/criteria/completion_criteria_self.php similarity index 100% rename from completion/completion_criteria_self.php rename to completion/criteria/completion_criteria_self.php diff --git a/completion/completion_criteria_unenrol.php b/completion/criteria/completion_criteria_unenrol.php similarity index 100% rename from completion/completion_criteria_unenrol.php rename to completion/criteria/completion_criteria_unenrol.php diff --git a/completion/cron.php b/completion/cron.php index 038577935bd..8f5ea24ab3d 100644 --- a/completion/cron.php +++ b/completion/cron.php @@ -207,7 +207,7 @@ function completion_cron_criteria() { foreach ($COMPLETION_CRITERIA_TYPES as $type) { $object = 'completion_criteria_'.$type; - require_once 'completion/'.$object.'.php'; + require_once $CFG->dirroot.'/completion/criteria/'.$object.'.php'; $class = new $object(); diff --git a/course/completion.php b/course/completion.php index 2a4d77a458f..6b38a889c3d 100644 --- a/course/completion.php +++ b/course/completion.php @@ -28,14 +28,14 @@ require_once('../config.php'); require_once('lib.php'); require_once($CFG->libdir.'/completionlib.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_self.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_date.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_unenrol.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_activity.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_duration.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_grade.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_role.php'); -require_once($CFG->dirroot.'/completion/completion_criteria_course.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_date.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_unenrol.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_duration.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_grade.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_role.php'); +require_once($CFG->dirroot.'/completion/criteria/completion_criteria_course.php'); require_once $CFG->libdir.'/gradelib.php'; require_once('completion_form.php'); diff --git a/lib/completionlib.php b/lib/completionlib.php index c26e49acaa9..c766b25e926 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -32,7 +32,7 @@ defined('MOODLE_INTERNAL') || die(); * Include the required completion libraries */ require_once $CFG->dirroot.'/completion/completion_aggregation.php'; -require_once $CFG->dirroot.'/completion/completion_criteria.php'; +require_once $CFG->dirroot.'/completion/criteria/completion_criteria.php'; require_once $CFG->dirroot.'/completion/completion_completion.php'; require_once $CFG->dirroot.'/completion/completion_criteria_completion.php'; diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 42d99027be8..5f998209551 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -405,7 +405,7 @@ function xmldb_main_upgrade($oldversion) { } if ($oldversion < 2012042300.02) { - require_once($CFG->dirroot.'/completion/completion_criteria.php'); + require_once($CFG->dirroot.'/completion/criteria/completion_criteria.php'); // Delete orphaned criteria which were left when modules were removed if ($DB->get_dbfamily() === 'mysql') { $sql = "DELETE cc FROM {course_completion_criteria} cc From 44e2f0fe72c6be2cd1ba0c3c0bdd7e9d4854b7e4 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Fri, 13 Jul 2012 11:44:55 +0800 Subject: [PATCH 005/106] MDL-34256: Grading table shows users with no submissions with "requires grading" filter Also hide the filters completely if there are no submission plugins enabled (offline assignment). --- mod/assign/gradingoptionsform.php | 4 +++- mod/assign/gradingtable.php | 2 +- mod/assign/locallib.php | 7 ++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mod/assign/gradingoptionsform.php b/mod/assign/gradingoptionsform.php index cf90c867108..3e6e54b14d5 100644 --- a/mod/assign/gradingoptionsform.php +++ b/mod/assign/gradingoptionsform.php @@ -52,7 +52,9 @@ class mod_assign_grading_options_form extends moodleform { $options = array('' => get_string('filternone', 'assign'), ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'), ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign')); - $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options); + if ($instance['submissionsenabled']) { + $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options); + } // quickgrading if ($instance['showquickgrading']) { diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php index abd5b7212b1..be0eb3d792f 100644 --- a/mod/assign/gradingtable.php +++ b/mod/assign/gradingtable.php @@ -105,7 +105,7 @@ class assign_grading_table extends table_sql implements renderable { $where .= ' AND s.timecreated > 0 '; } if ($filter == ASSIGN_FILTER_REQUIRE_GRADING) { - $where .= ' AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)'; + $where .= ' AND (s.timemodified > g.timemodified OR (s.timemodified IS NOT NULL AND g.timemodified IS NULL))'; } if (strpos($filter, ASSIGN_FILTER_SINGLE_USER) === 0) { $userfilter = (int) array_pop(explode('=', $filter)); diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php index 2fef79b1cda..c14747c4119 100644 --- a/mod/assign/locallib.php +++ b/mod/assign/locallib.php @@ -1724,6 +1724,7 @@ class assign { array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id, + 'submissionsenabled'=>$this->is_any_submission_plugin_enabled(), 'showquickgrading'=>$showquickgrading, 'quickgrading'=>$quickgrading), 'post', '', @@ -2654,7 +2655,11 @@ class assign { // Need submit permission to submit an assignment require_capability('mod/assign:grade', $this->context); - $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id, 'showquickgrading'=>false)); + $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, + 'contextid'=>$this->context->id, + 'userid'=>$USER->id, + 'submissionsenabled'=>$this->is_any_submission_plugin_enabled(), + 'showquickgrading'=>false)); if ($formdata = $mform->get_data()) { set_user_preference('assign_perpage', $formdata->perpage); set_user_preference('assign_filter', $formdata->filter); From 7f4771923322c0a5fb4275b6fad25178a0fe6c4f Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Fri, 13 Jul 2012 12:17:19 +0800 Subject: [PATCH 006/106] MDL-34067: Change default to on for text feedback comments in assignment This is the "default default" setting. --- mod/assign/feedback/comments/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/assign/feedback/comments/settings.php b/mod/assign/feedback/comments/settings.php index e3e290d1d54..f85cd5ad42e 100644 --- a/mod/assign/feedback/comments/settings.php +++ b/mod/assign/feedback/comments/settings.php @@ -24,5 +24,5 @@ $settings->add(new admin_setting_configcheckbox('assignfeedback_comments/default', new lang_string('default', 'assignfeedback_comments'), - new lang_string('default_help', 'assignfeedback_comments'), 0)); + new lang_string('default_help', 'assignfeedback_comments'), 1)); From 71df83d256597220dd76858cd36ea5a5ff5cfe1c Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Fri, 13 Jul 2012 12:40:25 +0800 Subject: [PATCH 007/106] MDL-34313: Deleting assignfeedback plugins deletes config for assignsubmission_plugin instead. --- mod/assign/adminlib.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mod/assign/adminlib.php b/mod/assign/adminlib.php index a6b2eb11250..43c1e7d8e16 100644 --- a/mod/assign/adminlib.php +++ b/mod/assign/adminlib.php @@ -269,7 +269,7 @@ class assign_plugin_manager { if ($confirm) { // Delete any configuration records. - if (!unset_all_config_for_plugin('assignsubmission_' . $plugin)) { + if (!unset_all_config_for_plugin($this->subtype . '_' . $plugin)) { $this->error = $OUTPUT->notification(get_string('errordeletingconfig', 'admin', $this->subtype . '_' . $plugin)); } @@ -282,7 +282,8 @@ class assign_plugin_manager { $DB->delete_records('assign_plugin_config', array('plugin'=>$plugin, 'subtype'=>$this->subtype)); // Then the tables themselves - drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $this->subtype . '/' .$plugin. '/db/install.xml', false); + $shortsubtype = substr($this->subtype, strlen('assign')); + drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $shortsubtype . '/' .$plugin. '/db/install.xml', false); // Remove event handlers and dequeue pending events events_uninstall($this->subtype . '_' . $plugin); From 65dcd906e3ba8fec66c4e7c7aa254046ed59edf3 Mon Sep 17 00:00:00 2001 From: Andrew Robert Nicols Date: Fri, 13 Jul 2012 15:01:37 +0100 Subject: [PATCH 008/106] MDL-34322 Don't display empty navigation nodes which have no link --- blocks/navigation/renderer.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blocks/navigation/renderer.php b/blocks/navigation/renderer.php index fe91aed2b10..4c3d28cf507 100644 --- a/blocks/navigation/renderer.php +++ b/blocks/navigation/renderer.php @@ -77,6 +77,11 @@ class block_navigation_renderer extends plugin_renderer_base { $isexpandable = (empty($expansionlimit) || ($item->type > navigation_node::TYPE_ACTIVITY || $item->type < $expansionlimit) || ($item->contains_active_node() && $item->children->count() > 0)); $isbranch = $isexpandable && ($item->children->count() > 0 || ($item->has_children() && (isloggedin() || $item->type <= navigation_node::TYPE_CATEGORY))); + // Skip elements which have no content and no action - no point in showing them + if (!$isexpandable && empty($item->action)) { + continue; + } + $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY || $item->type == navigation_node::TYPE_RESOURCE) && $item->icon instanceof renderable); if ($hasicon) { From f70079b9bf6fc5097ad96e57efd40ef4a9ea35f0 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Fri, 13 Jul 2012 13:11:46 +0800 Subject: [PATCH 009/106] MDL-2283: Display number of assignment submissions that need grading in the grading summary --- mod/assign/lang/en/assign.php | 1 + mod/assign/locallib.php | 24 +++++++++++++++++++++++- mod/assign/renderable.php | 7 ++++++- mod/assign/renderer.php | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php index 251cff50030..b39750dc47c 100644 --- a/mod/assign/lang/en/assign.php +++ b/mod/assign/lang/en/assign.php @@ -173,6 +173,7 @@ $string['nousersselected'] = 'No users selected'; $string['numberofdraftsubmissions'] = 'Drafts'; $string['numberofparticipants'] = 'Participants'; $string['numberofsubmittedassignments'] = 'Submitted'; +$string['numberofsubmissionsneedgrading'] = 'Needs grading'; $string['offline'] = 'No online submissions required'; $string['overdue'] = 'Assignment is overdue by: {$a}'; $string['outlinegrade'] = 'Grade: {$a}'; diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php index 85ff77eb95e..2fc41952b0f 100644 --- a/mod/assign/locallib.php +++ b/mod/assign/locallib.php @@ -967,6 +967,27 @@ class assign { return count_enrolled_users($this->context, "mod/assign:submit", $currentgroup); } + /** + * Load a count of users submissions in the current module that require grading + * This means the submission modification time is more recent than the + * grading modification time. + * + * @return int number of matching submissions + */ + public function count_submissions_need_grading() { + global $DB; + + $params = array($this->get_course_module()->instance); + + return $DB->count_records_sql("SELECT COUNT('x') + FROM {assign_submission} s + LEFT JOIN {assign_grades} g ON s.assignment = g.assignment AND s.userid = g.userid + WHERE s.assignment = ? + AND s.timemodified IS NOT NULL + AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)", + $params); + } + /** * Load a count of users enrolled in the current course with the specified permission and group (optional) * @@ -2091,7 +2112,8 @@ class assign { $this->is_any_submission_plugin_enabled(), $this->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED), $this->get_instance()->duedate, - $this->get_course_module()->id + $this->get_course_module()->id, + $this->count_submissions_need_grading() )); } $grade = $this->get_user_grade($USER->id, false); diff --git a/mod/assign/renderable.php b/mod/assign/renderable.php index cb1daf93bf0..5e710a45125 100644 --- a/mod/assign/renderable.php +++ b/mod/assign/renderable.php @@ -405,6 +405,8 @@ class assign_grading_summary implements renderable { var $submissionsenabled = false; /** @var int submissionssubmittedcount - The number of submissions in submitted status */ var $submissionssubmittedcount = 0; + /** @var int submissionsneedgradingcount - The number of submissions that need grading */ + var $submissionsneedgradingcount = 0; /** @var int duedate - The assignment due date (if one is set) */ var $duedate = 0; /** @var int coursemoduleid - The assignment course module id */ @@ -421,7 +423,9 @@ class assign_grading_summary implements renderable { * @param int $duedate * @param int $coursemoduleid */ - public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount, $submissionsenabled, $submissionssubmittedcount, $duedate, $coursemoduleid) { + public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount, + $submissionsenabled, $submissionssubmittedcount, + $duedate, $coursemoduleid, $submissionsneedgradingcount) { $this->participantcount = $participantcount; $this->submissiondraftsenabled = $submissiondraftsenabled; $this->submissiondraftscount = $submissiondraftscount; @@ -429,6 +433,7 @@ class assign_grading_summary implements renderable { $this->submissionssubmittedcount = $submissionssubmittedcount; $this->duedate = $duedate; $this->coursemoduleid = $coursemoduleid; + $this->submissionsneedgradingcount = $submissionsneedgradingcount; } diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php index ab3af8a60b7..8ffe18f27e4 100644 --- a/mod/assign/renderer.php +++ b/mod/assign/renderer.php @@ -248,6 +248,8 @@ class mod_assign_renderer extends plugin_renderer_base { if ($summary->submissionsenabled) { $this->add_table_row_tuple($t, get_string('numberofsubmittedassignments', 'assign'), $summary->submissionssubmittedcount); + $this->add_table_row_tuple($t, get_string('numberofsubmissionsneedgrading', 'assign'), + $summary->submissionsneedgradingcount); } $time = time(); From da099b12a0dacff83b2f09bd3c0c061a18a30bf7 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Fri, 13 Jul 2012 10:38:13 +0800 Subject: [PATCH 010/106] MDL-34272: Assignment module displays all assignments on my moodle instead of just open ones --- mod/assign/lib.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mod/assign/lib.php b/mod/assign/lib.php index caccf102877..a6cdba7f1fc 100644 --- a/mod/assign/lib.php +++ b/mod/assign/lib.php @@ -212,16 +212,13 @@ function assign_print_overview($courses, &$htmlarray) { // Do assignment_base::isopen() here without loading the whole thing for speed foreach ($assignments as $key => $assignment) { $time = time(); + $isopen = $assignment->allowsubmissionsfromdate <= $time; if ($assignment->duedate) { if ($assignment->preventlatesubmissions) { - $isopen = ($assignment->allowsubmissionsfromdate <= $time && $time <= $assignment->duedate); - } else { - $isopen = ($assignment->allowsubmissionsfromdate <= $time); + $isopen = ($isopen && $time <= $assignment->duedate); } } - if (empty($isopen) || empty($assignment->duedate)) { - $assignmentids[] = $assignment->id; - } else { + if ($isopen) { $assignmentids[] = $assignment->id; } } @@ -265,6 +262,10 @@ function assign_print_overview($courses, &$htmlarray) { AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams)); foreach ($assignments as $assignment) { + // Do not show assignments that are not open + if (!in_array($assignment->id, $assignmentids)) { + continue; + } $str = '
'.$strassignment. ': '. 'visible ? '':' class="dimmed"'). 'title="'.$strassignment.'" href="'.$CFG->wwwroot. From fef7025c5e3bb5b130d2f91fe1f3547ac827727b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 17 Jul 2012 10:15:14 +0800 Subject: [PATCH 011/106] MDL-32665 mod_chat: disabled popup notifications in the chat windows --- mod/chat/gui_ajax/index.php | 1 + mod/chat/gui_basic/index.php | 1 + 2 files changed, 2 insertions(+) diff --git a/mod/chat/gui_ajax/index.php b/mod/chat/gui_ajax/index.php index 6955693a6c1..db7f3401c05 100644 --- a/mod/chat/gui_ajax/index.php +++ b/mod/chat/gui_ajax/index.php @@ -11,6 +11,7 @@ if ($groupid !== 0) { $url->param('groupid', $groupid); } $PAGE->set_url($url); +$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window $chat = $DB->get_record('chat', array('id'=>$id), '*', MUST_EXIST); $course = $DB->get_record('course', array('id'=>$chat->course), '*', MUST_EXIST); diff --git a/mod/chat/gui_basic/index.php b/mod/chat/gui_basic/index.php index 82e02cba386..aa79bd540c6 100644 --- a/mod/chat/gui_basic/index.php +++ b/mod/chat/gui_basic/index.php @@ -44,6 +44,7 @@ $context = get_context_instance(CONTEXT_MODULE, $cm->id); require_login($course, false, $cm); require_capability('mod/chat:chat', $context); $PAGE->set_pagelayout('base'); +$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window /// Check to see if groups are being used here if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used From 7edfa373fda196d21668fb863592200a80dd7f17 Mon Sep 17 00:00:00 2001 From: Michael Aherne Date: Thu, 12 Jul 2012 13:16:47 +0100 Subject: [PATCH 012/106] MDL-24298 news block Remove "more" link for improved accessibility --- blocks/news_items/block_news_items.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/blocks/news_items/block_news_items.php b/blocks/news_items/block_news_items.php index 6fcd152ae72..3561c4f762b 100644 --- a/blocks/news_items/block_news_items.php +++ b/blocks/news_items/block_news_items.php @@ -84,9 +84,7 @@ class block_news_items extends block_base { '
'. '
'.userdate($discussion->modified, $strftimerecent).'
'. '
'.fullname($discussion).'
'. - '
'. + ''. "\n"; } $text .= "\n"; From a32dabc26038861aa6f065a65b0e73a1064cbe86 Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Mon, 9 Jul 2012 20:50:35 +0100 Subject: [PATCH 013/106] MDL-33927 Filemanager - enforce the maxfiles limit on form submission --- lang/en/form.php | 1 + lib/formslib.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lang/en/form.php b/lang/en/form.php index fbd8c9d46b5..d55667d4b3e 100644 --- a/lang/en/form.php +++ b/lang/en/form.php @@ -30,6 +30,7 @@ $string['display'] = 'Display'; $string['err_alphanumeric'] = 'You must enter only letters or numbers here.'; $string['err_email'] = 'You must enter a valid email address here.'; $string['err_lettersonly'] = 'You must enter only letters here.'; +$string['err_maxfiles'] = 'You must not attach more than {$a} files here.'; $string['err_maxlength'] = 'You must enter not more than {$a->format} characters here.'; $string['err_minlength'] = 'You must enter at least {$a->format} characters here.'; $string['err_nonzero'] = 'You must enter a number not starting with a 0 here.'; diff --git a/lib/formslib.php b/lib/formslib.php index 306c4e5d2b8..e970c6db1cb 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -385,6 +385,22 @@ abstract class moodleform { } } } + // Check all the filemanager elements to make sure they do not have too many + // files in them. + foreach ($mform->_elements as $element) { + if ($element->_type == 'filemanager') { + $maxfiles = $element->getMaxfiles(); + if ($maxfiles > 0) { + $draftid = (int)$element->getValue(); + $fs = get_file_storage(); + $context = context_user::instance($USER->id); + $files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, '', false); + if (count($files) > $maxfiles) { + $errors[$element->getName()] = get_string('err_maxfiles', 'form', $maxfiles); + } + } + } + } if (empty($errors)) { return true; } else { From bb5cc0e964bf2c506e02d3588db302e4736399a1 Mon Sep 17 00:00:00 2001 From: Dan Marsden Date: Wed, 18 Jul 2012 10:32:46 +1200 Subject: [PATCH 014/106] MDL-34374 SCORM prevent skipview being set to always when used inside a SCORM course format. --- mod/scorm/locallib.php | 10 +++++++--- mod/scorm/mod_form.php | 9 ++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php index 505905afe3a..ab304dfad94 100644 --- a/mod/scorm/locallib.php +++ b/mod/scorm/locallib.php @@ -22,6 +22,10 @@ define('SCORM_UPDATE_NEVER', '0'); define('SCORM_UPDATE_EVERYDAY', '2'); define('SCORM_UPDATE_EVERYTIME', '3'); +define('SCORM_SKIPVIEW_NEVER', '0'); +define('SCORM_SKIPVIEW_FIRST', '1'); +define('SCORM_SKIPVIEW_ALWAYS', '2'); + define('SCO_ALL', 0); define('SCO_DATA', 1); define('SCO_ONLY', 2); @@ -109,9 +113,9 @@ function scorm_get_what_grade_array() { * @return array an array of skip view options */ function scorm_get_skip_view_array() { - return array(0 => get_string('never'), - 1 => get_string('firstaccess', 'scorm'), - 2 => get_string('always')); + return array(SCORM_SKIPVIEW_NEVER => get_string('never'), + SCORM_SKIPVIEW_FIRST => get_string('firstaccess', 'scorm'), + SCORM_SKIPVIEW_ALWAYS => get_string('always')); } /** diff --git a/mod/scorm/mod_form.php b/mod/scorm/mod_form.php index d558c6b2b89..4b0837cb163 100644 --- a/mod/scorm/mod_form.php +++ b/mod/scorm/mod_form.php @@ -124,7 +124,14 @@ class mod_scorm_mod_form extends moodleform_mod { $mform->setAdvanced('winoptgrp', $cfg_scorm->winoptgrp_adv); // Skip view page - $mform->addElement('select', 'skipview', get_string('skipview', 'scorm'), scorm_get_skip_view_array()); + $skipviewoptions = scorm_get_skip_view_array(); + if ($COURSE->format == 'scorm') { // Remove option that would cause a constant redirect. + unset($skipviewoptions[SCORM_SKIPVIEW_ALWAYS]); + if ($cfg_scorm->skipview == SCORM_SKIPVIEW_ALWAYS) { + $cfg_scorm->skipview = SCORM_SKIPVIEW_FIRST; + } + } + $mform->addElement('select', 'skipview', get_string('skipview', 'scorm'), $skipviewoptions); $mform->addHelpButton('skipview', 'skipview', 'scorm'); $mform->setDefault('skipview', $cfg_scorm->skipview); $mform->setAdvanced('skipview', $cfg_scorm->skipview_adv); From 1258391a50d214ecaac72d0f3c5a97bf768b94ed Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 19 Jul 2012 12:59:46 +0800 Subject: [PATCH 015/106] MDL-34400 Alfresco: Updated PHP SDK to v0.1 --- lib/alfresco/Service/Association.php | 108 +- lib/alfresco/Service/BaseObject.php | 286 ++- lib/alfresco/Service/ChildAssociation.php | 146 +- lib/alfresco/Service/ContentData.php | 577 +++--- lib/alfresco/Service/Functions.php | 223 ++- lib/alfresco/Service/Logger/Logger.php | 174 +- lib/alfresco/Service/Logger/LoggerConfig.php | 82 +- lib/alfresco/Service/NamespaceMap.php | 236 ++- lib/alfresco/Service/Node.php | 1622 ++++++++--------- lib/alfresco/Service/Repository.php | 266 ++- lib/alfresco/Service/Session.php | 548 +++--- lib/alfresco/Service/SpacesStore.php | 100 +- lib/alfresco/Service/Store.php | 154 +- lib/alfresco/Service/Version.php | 394 ++-- lib/alfresco/Service/VersionHistory.php | 154 +- .../Service/WebService/AlfrescoWebService.php | 229 ++- .../Service/WebService/WebServiceFactory.php | 121 +- 17 files changed, 2654 insertions(+), 2766 deletions(-) diff --git a/lib/alfresco/Service/Association.php b/lib/alfresco/Service/Association.php index 74c96f5eab9..f7349a8fd00 100644 --- a/lib/alfresco/Service/Association.php +++ b/lib/alfresco/Service/Association.php @@ -1,57 +1,51 @@ -_from = $from; - $this->_to = $to; - $this->_type = $type; - } - - public function getFrom() - { - return $this->_from; - } - - public function getTo() - { - return $this->_to; - } - - public function getType() - { - return $this->_type; - } -} - -?> +. + */ + +class Association extends BaseObject +{ + private $_from; + private $_to; + private $_type; + + public function __construct($from, $to, $type) + { + $this->_from = $from; + $this->_to = $to; + $this->_type = $type; + } + + public function getFrom() + { + return $this->_from; + } + + public function getTo() + { + return $this->_to; + } + + public function getType() + { + return $this->_type; + } +} + +?> diff --git a/lib/alfresco/Service/BaseObject.php b/lib/alfresco/Service/BaseObject.php index db0d71e6ef2..427b9e1d3ae 100644 --- a/lib/alfresco/Service/BaseObject.php +++ b/lib/alfresco/Service/BaseObject.php @@ -1,147 +1,141 @@ -$methodName(); - } - } - - public function __set($name, $value) - { - $methodName = $name; - $methodName[0] = strtoupper($methodName[0]); - $methodName = 'set' . $methodName; - - if (method_exists($this, $methodName) == true) - { - return $this->$methodName($value); - } - } - - protected function resultSetToNodes($session, $store, $resultSet) - { - $return = array(); - if (isset($resultSet->rows) == true) - { - if (is_array($resultSet->rows) == true) - { - foreach($resultSet->rows as $row) - { - $id = $row->node->id; - $return[] = $session->getNode($store, $id); - } - } - else - { - $id = $resultSet->rows->node->id; - $return[] = $session->getNode($store, $id); - } - } - - return $return; - } - - protected function resultSetToMap($resultSet) - { - $return = array(); - if (isset($resultSet->rows) == true) - { - if (is_array($resultSet->rows) == true) - { - foreach($resultSet->rows as $row) - { - $return[] = $this->columnsToMap($row->columns); - } - } - else - { - $return[] = $this->columnsToMap($resultSet->rows->columns); - } - - } - - return $return; - } - - private function columnsToMap($columns) - { - $return = array(); - - foreach ($columns as $column) - { - $return[$column->name] = $column->value; - } - - return $return; - } - - protected function remove_array_value($value, &$array) - { - if ($array != null) - { - if (in_array($value, $array) == true) - { - foreach ($array as $index=>$value2) - { - if ($value == $value2) - { - unset($array[$index]); - } - } - } - } - } - - protected function isContentData($value) - { - $index = strpos($value, "contentUrl="); - if ($index === false) - { - return false; - } - else - { - if ($index == 0) - { - return true; - } - else - { - return false; - } - } - } -} +. + */ + +class BaseObject +{ + public function __get($name) + { + $methodName = $name; + $methodName[0] = strtoupper($methodName[0]); + $methodName = 'get' . $methodName; + + if (method_exists($this, $methodName) == true) + { + return $this->$methodName(); + } + } + + public function __set($name, $value) + { + $methodName = $name; + $methodName[0] = strtoupper($methodName[0]); + $methodName = 'set' . $methodName; + + if (method_exists($this, $methodName) == true) + { + return $this->$methodName($value); + } + } + + protected function resultSetToNodes($session, $store, $resultSet) + { + $return = array(); + if (isset($resultSet->rows) == true) + { + if (is_array($resultSet->rows) == true) + { + foreach($resultSet->rows as $row) + { + $id = $row->node->id; + $return[] = $session->getNode($store, $id); + } + } + else + { + $id = $resultSet->rows->node->id; + $return[] = $session->getNode($store, $id); + } + } + + return $return; + } + + protected function resultSetToMap($resultSet) + { + $return = array(); + if (isset($resultSet->rows) == true) + { + if (is_array($resultSet->rows) == true) + { + foreach($resultSet->rows as $row) + { + $return[] = $this->columnsToMap($row->columns); + } + } + else + { + $return[] = $this->columnsToMap($resultSet->rows->columns); + } + + } + + return $return; + } + + private function columnsToMap($columns) + { + $return = array(); + + foreach ($columns as $column) + { + $return[$column->name] = $column->value; + } + + return $return; + } + + protected function remove_array_value($value, &$array) + { + if ($array != null) + { + if (in_array($value, $array) == true) + { + foreach ($array as $index=>$value2) + { + if ($value == $value2) + { + unset($array[$index]); + } + } + } + } + } + + protected function isContentData($value) + { + $index = strpos($value, "contentUrl="); + if ($index === false) + { + return false; + } + else + { + if ($index == 0) + { + return true; + } + else + { + return false; + } + } + } +} ?> \ No newline at end of file diff --git a/lib/alfresco/Service/ChildAssociation.php b/lib/alfresco/Service/ChildAssociation.php index b9f4adc3af8..41c3dad5257 100644 --- a/lib/alfresco/Service/ChildAssociation.php +++ b/lib/alfresco/Service/ChildAssociation.php @@ -1,76 +1,70 @@ -_parent = $parent; - $this->_child = $child; - $this->_type = $type; - $this->_name = $name; - $this->_isPrimary = $isPrimary; - $this->_nthSibling = $nthSibling; - } - - public function getParent() - { - return $this->_parent; - } - - public function getChild() - { - return $this->_child; - } - - public function getType() - { - return $this->_type; - } - - public function getName() - { - return $this->_name; - } - - public function getIsPrimary() - { - return $this->_isPrimary; - } - - public function getNthSibling() - { - return $this->_nthSibling; - } -} -?> +. + */ + +class ChildAssociation extends BaseObject +{ + private $_parent; + private $_child; + private $_type; + private $_name; + private $_isPrimary; + private $_nthSibling; + + public function __construct($parent, $child, $type, $name, $isPrimary=false, $nthSibling=0) + { + $this->_parent = $parent; + $this->_child = $child; + $this->_type = $type; + $this->_name = $name; + $this->_isPrimary = $isPrimary; + $this->_nthSibling = $nthSibling; + } + + public function getParent() + { + return $this->_parent; + } + + public function getChild() + { + return $this->_child; + } + + public function getType() + { + return $this->_type; + } + + public function getName() + { + return $this->_name; + } + + public function getIsPrimary() + { + return $this->_isPrimary; + } + + public function getNthSibling() + { + return $this->_nthSibling; + } +} +?> diff --git a/lib/alfresco/Service/ContentData.php b/lib/alfresco/Service/ContentData.php index 25a3d78325d..6c392a26ffd 100644 --- a/lib/alfresco/Service/ContentData.php +++ b/lib/alfresco/Service/ContentData.php @@ -1,292 +1,285 @@ -libdir."/alfresco/Service/Functions.php"); - -class ContentData extends BaseObject -{ - private $_isPopulated = false; - private $_isDirty = false; - - private $_node; - private $_property; - - private $_mimetype; - private $_size; - private $_encoding; - private $_url; - private $_newContent; - private $_newFileContent; - - public function __construct($node, $property, $mimetype=null, $encoding=null, $size=-1) - { - $this->_node = $node; - $this->_property = $property; - $this->_mimetype = $mimetype; - $this->_encoding = $encoding; - if ($size != -1) - { - $this->size = $size; - } - $this->_isPopulated = false; - } - - public function setPropertyDetails($node, $property) - { - $this->_node = $node; - $this->_property = $property; - } - - public function __toString() - { - $this->populateContentData(); - return "mimetype=".$this->mimetype."|encoding=".$this->encoding."|size=".$this->size; - } - - public function getNode() - { - return $this->_node; - } - - public function getProperty() - { - return $this->_property; - } - - public function getIsDirty() - { - return $this->_isDirty; - } - - public function getMimetype() - { - $this->populateContentData(); - return $this->_mimetype; - } - - public function setMimetype($mimetype) - { - $this->populateContentData(); - $this->_mimetype = $mimetype; - } - - public function getSize() - { - $this->populateContentData(); - return $this->_size; - } - - public function getEncoding() - { - $this->populateContentData(); - return $this->_encoding; - } - - public function setEncoding($encoding) - { - $this->populateContentData(); - $this->_encoding = $encoding; - } - - public function getUrl() - { - // TODO what should be returned if the content has been updated?? - - $this->populateContentData(); - $result = null; - if ($this->_url != null) - { - $result = $this->_url."?ticket=".$this->_node->session->ticket; - } - return $result; - } - - public function getGuestUrl() - { - // TODO what should be returned if the content has been updated?? - - $this->populateContentData(); - $result = null; - if ($this->_url != null) - { - $result = $this->_url."?guest=true"; - } - return $result; - } - - public function getContent() - { - $this->populateContentData(); - - $result = null; - if ($this->_isDirty == true) - { - if ($this->_newFileContent != null) - { - $handle = fopen($this->_newFileContent, "rb"); - $result = stream_get_contents($handle); - fclose($handle); - } - else if ($this->_newContent != null) - { - $result = $this->_newContent; - } - } - else - { - if ($this->getUrl() != null) - { - $handle = fopen($this->getUrl(), "rb"); - $result = stream_get_contents($handle); - fclose($handle); - } - } - return $result; - } - - public function setContent($content) - { - $this->populateContentData(); - $this->_isDirty = true; - $this->_newContent = $content; - } - - public function writeContentFromFile($fileName) - { - $this->populateContentData(); - $this->_isDirty = true; - $this->_newFileContent = $fileName; - } - - public function readContentToFile($fileName) - { - $handle = fopen($fileName, "wb"); - fwrite($handle, $this->getContent()); - fclose($handle); - } - - public function onBeforeSave(&$statements, $where) - { - if ($this->_isDirty == true) - { - // Check mimetype has been set - if ($this->_mimetype == null) - { - throw new Exception("A mime type for the content property ".$this->_property." on node ".$this->_node->__toString()." must be set"); - } - - // If a file has been specified then read content from there - //$content = null; - if ($this->_newFileContent != null) - { - // Upload the content to the repository - $contentData = upload_file($this->node->session, $this->_newFileContent, $this->_mimetype, $this->_encoding); - - // Set the content property value - $this->addStatement( - $statements, - "update", - array("property" => array( - "name" => $this->property, - "isMultiValue" => false, - "value" => $contentData)) + $where); - } - else - { - // Add the writeContent statement - $this->addStatement( - $statements, - "writeContent", - array( - "property" => $this->_property, - "content" => $this->_newContent, - "format" => array( - "mimetype" => $this->_mimetype, - "encoding" => $this->_encoding)) + - $where); - } - } - } - - public function onAfterSave() - { - $this->_isDirty = false; - $this->_isPopulated = false; - $this->_mimetype = null; - $this->__size = null; - $this->__encoding = null; - $this->__url = null; - $this->__newContent = null; - } - - private function populateContentData() - { - //echo "isPopulated:".$this->_isPopulated."; node:".$this->_node."; property:".$this->_property."
"; - if ($this->_isPopulated == false && $this->_node != null && $this->_property != null && $this->_node->isNewNode == false) - { - $result = $this->_node->session->contentService->read( array( - "items" => array( - "nodes" => array( - "store" => $this->_node->store->__toArray(), - "uuid" => $this->_node->id)), - "property" => $this->_property) ); - if (isset($result->content) == true) - { - if (isset($result->content->length) == true) - { - $this->_size = $result->content->length; - } - if (isset($result->content->format->mimetype) == true) - { - $this->_mimetype = $result->content->format->mimetype; - } - if (isset($result->content->format->encoding) == true) - { - $this->_encoding = $result->content->format->encoding; - } - if (isset($result->content->url) == true) - { - $this->_url = $result->content->url; - } - } - - $this->_isPopulated = true; - } - } - - private function addStatement(&$statements, $statement, $body) - { - $result = array(); - if (array_key_exists($statement, $statements) == true) - { - $result = $statements[$statement]; - } - $result[] = $body; - $statements[$statement] = $result; - } -} -?> +. + */ + +require_once("Alfresco/Service/Functions.php"); + +class ContentData extends BaseObject +{ + private $_isPopulated = false; + private $_isDirty = false; + + private $_node; + private $_property; + + private $_mimetype; + private $_size; + private $_encoding; + private $_url; + private $_newContent; + private $_newFileContent; + + public function __construct($node, $property, $mimetype=null, $encoding=null, $size=-1) + { + $this->_node = $node; + $this->_property = $property; + $this->_mimetype = $mimetype; + $this->_encoding = $encoding; + if ($size != -1) + { + $this->size = $size; + } + $this->_isPopulated = false; + } + + public function setPropertyDetails($node, $property) + { + $this->_node = $node; + $this->_property = $property; + } + + public function __toString() + { + $this->populateContentData(); + return "mimetype=".$this->mimetype."|encoding=".$this->encoding."|size=".$this->size; + } + + public function getNode() + { + return $this->_node; + } + + public function getProperty() + { + return $this->_property; + } + + public function getIsDirty() + { + return $this->_isDirty; + } + + public function getMimetype() + { + $this->populateContentData(); + return $this->_mimetype; + } + + public function setMimetype($mimetype) + { + $this->populateContentData(); + $this->_mimetype = $mimetype; + } + + public function getSize() + { + $this->populateContentData(); + return $this->_size; + } + + public function getEncoding() + { + $this->populateContentData(); + return $this->_encoding; + } + + public function setEncoding($encoding) + { + $this->populateContentData(); + $this->_encoding = $encoding; + } + + public function getUrl() + { + // TODO what should be returned if the content has been updated?? + + $this->populateContentData(); + $result = null; + if ($this->_url != null) + { + $result = $this->_url."?ticket=".$this->_node->session->ticket; + } + return $result; + } + + public function getGuestUrl() + { + // TODO what should be returned if the content has been updated?? + + $this->populateContentData(); + $result = null; + if ($this->_url != null) + { + $result = $this->_url."?guest=true"; + } + return $result; + } + + public function getContent() + { + $this->populateContentData(); + + $result = null; + if ($this->_isDirty == true) + { + if ($this->_newFileContent != null) + { + $handle = fopen($this->_newFileContent, "rb"); + $result = stream_get_contents($handle); + fclose($handle); + } + else if ($this->_newContent != null) + { + $result = $this->_newContent; + } + } + else + { + if ($this->getUrl() != null) + { + $handle = fopen($this->getUrl(), "rb"); + $result = stream_get_contents($handle); + fclose($handle); + } + } + return $result; + } + + public function setContent($content) + { + $this->populateContentData(); + $this->_isDirty = true; + $this->_newContent = $content; + } + + public function writeContentFromFile($fileName) + { + $this->populateContentData(); + $this->_isDirty = true; + $this->_newFileContent = $fileName; + } + + public function readContentToFile($fileName) + { + $handle = fopen($fileName, "wb"); + fwrite($handle, $this->getContent()); + fclose($handle); + } + + public function onBeforeSave(&$statements, $where) + { + if ($this->_isDirty == true) + { + // Check mimetype has been set + if ($this->_mimetype == null) + { + throw new Exception("A mime type for the content property ".$this->_property." on node ".$this->_node->__toString()." must be set"); + } + + // If a file has been specified then read content from there + //$content = null; + if ($this->_newFileContent != null) + { + // Upload the content to the repository + $contentData = upload_file($this->node->session, $this->_newFileContent, $this->_mimetype, $this->_encoding); + + // Set the content property value + $this->addStatement( + $statements, + "update", + array("property" => array( + "name" => $this->property, + "isMultiValue" => false, + "value" => $contentData)) + $where); + } + else + { + // Add the writeContent statement + $this->addStatement( + $statements, + "writeContent", + array( + "property" => $this->_property, + "content" => $this->_newContent, + "format" => array( + "mimetype" => $this->_mimetype, + "encoding" => $this->_encoding)) + + $where); + } + } + } + + public function onAfterSave() + { + $this->_isDirty = false; + $this->_isPopulated = false; + $this->_mimetype = null; + $this->__size = null; + $this->__encoding = null; + $this->__url = null; + $this->__newContent = null; + } + + private function populateContentData() + { + //echo "isPopulated:".$this->_isPopulated."; node:".$this->_node."; property:".$this->_property."
"; + if ($this->_isPopulated == false && $this->_node != null && $this->_property != null && $this->_node->isNewNode == false) + { + $result = $this->_node->session->contentService->read( array( + "items" => array( + "nodes" => array( + "store" => $this->_node->store->__toArray(), + "uuid" => $this->_node->id)), + "property" => $this->_property) ); + if (isset($result->content) == true) + { + if (isset($result->content->length) == true) + { + $this->_size = $result->content->length; + } + if (isset($result->content->format->mimetype) == true) + { + $this->_mimetype = $result->content->format->mimetype; + } + if (isset($result->content->format->encoding) == true) + { + $this->_encoding = $result->content->format->encoding; + } + if (isset($result->content->url) == true) + { + $this->_url = $result->content->url; + } + } + + $this->_isPopulated = true; + } + } + + private function addStatement(&$statements, $statement, $body) + { + $result = array(); + if (array_key_exists($statement, $statements) == true) + { + $result = $statements[$statement]; + } + $result[] = $body; + $statements[$statement] = $result; + } +} +?> diff --git a/lib/alfresco/Service/Functions.php b/lib/alfresco/Service/Functions.php index fdc9b461883..a0918e38ff8 100644 --- a/lib/alfresco/Service/Functions.php +++ b/lib/alfresco/Service/Functions.php @@ -1,115 +1,108 @@ -libdir."/alfresco/Service/Repository.php"); - require_once($CFG->libdir."/alfresco/Service/Session.php"); - - /** - * Uploads a file into content store and returns the content data string which - * can be used to populate a content property. - * - * @param $session the session - * @param $filePath the file location - * @return String the content data that can be used to update the content property - */ - function upload_file($session, $filePath, $mimetype=null, $encoding=null) - { - $result = null; - - // Check for the existance of the file - if (file_exists($filePath) == false) - { - throw new Exception("The file ".$filePath."does no exist."); - } - - // Get the file name and size - $fileName = basename($filePath); - $fileSize = filesize($filePath); - - // Get the address and the - $host = $session->repository->host; - $port = $session->repository->port; - - // Get the IP address for the target host - $address = gethostbyname($host); - - // Create a TCP/IP socket - $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($socket === false) - { - throw new Exception ("socket_create() failed: reason: " . socket_strerror(socket_last_error())); - } - - // Connect the socket to the repository - $result = socket_connect($socket, $address, $port); - if ($result === false) - { - throw new Exception("socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket))); - } - - // Write the request header onto the socket - $url = "/alfresco/upload/".urlencode($fileName)."?ticket=".$session->ticket; - if ($mimetype != null) - { - // Add mimetype if specified - $url .= "&mimetype=".$mimetype; - } - if ($encoding != null) - { - // Add encoding if specified - $url .= "&encoding=".$encoding; - } - $in = "PUT ".$url." HTTP/1.1\r\n". - "Content-Length: ".$fileSize."\r\n". - "Host: ".$address.":".$port."\r\n". - "Connection: Keep-Alive\r\n". - "\r\n"; - socket_write($socket, $in, strlen($in)); - - // Write the content found in the file onto the socket - $handle = fopen($filePath, "r"); - while (feof($handle) == false) - { - $content = fread($handle, 1024); - socket_write($socket, $content, strlen($content)); - } - fclose($handle); - - // Read the response - $recv = socket_read ($socket, 2048, PHP_BINARY_READ); - $index = strpos($recv, "contentUrl"); - if ($index !== false) - { - $result = substr($recv, $index); - } - - // Close the socket - socket_close($socket); - - return $result; - } -?> +. + */ + + require_once("Alfresco/Service/Repository.php"); + require_once("Alfresco/Service/Session.php"); + + /** + * Uploads a file into content store and returns the content data string which + * can be used to populate a content property. + * + * @param $session the session + * @param $filePath the file location + * @return String the content data that can be used to update the content property + */ + function upload_file($session, $filePath, $mimetype=null, $encoding=null) + { + $result = null; + + // Check for the existance of the file + if (file_exists($filePath) == false) + { + throw new Exception("The file ".$filePath."does no exist."); + } + + // Get the file name and size + $fileName = basename($filePath); + $fileSize = filesize($filePath); + + // Get the address and the + $host = $session->repository->host; + $port = $session->repository->port; + + // Get the IP address for the target host + $address = gethostbyname($host); + + // Create a TCP/IP socket + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($socket === false) + { + throw new Exception ("socket_create() failed: reason: " . socket_strerror(socket_last_error())); + } + + // Connect the socket to the repository + $result = socket_connect($socket, $address, $port); + if ($result === false) + { + throw new Exception("socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket))); + } + + // Write the request header onto the socket + $url = "/alfresco/upload/".urlencode($fileName)."?ticket=".$session->ticket; + if ($mimetype != null) + { + // Add mimetype if specified + $url .= "&mimetype=".$mimetype; + } + if ($encoding != null) + { + // Add encoding if specified + $url .= "&encoding=".$encoding; + } + $in = "PUT ".$url." HTTP/1.1\r\n". + "Content-Length: ".$fileSize."\r\n". + "Host: ".$address.":".$port."\r\n". + "Connection: Keep-Alive\r\n". + "\r\n"; + socket_write($socket, $in, strlen($in)); + + // Write the content found in the file onto the socket + $handle = fopen($filePath, "r"); + while (feof($handle) == false) + { + $content = fread($handle, 1024); + socket_write($socket, $content, strlen($content)); + } + fclose($handle); + + // Read the response + $recv = socket_read ($socket, 2048, PHP_BINARY_READ); + $index = strpos($recv, "contentUrl"); + if ($index !== false) + { + $result = substr($recv, $index); + } + + // Close the socket + socket_close($socket); + + return $result; + } +?> diff --git a/lib/alfresco/Service/Logger/Logger.php b/lib/alfresco/Service/Logger/Logger.php index 6d2645080f7..54e77d27be8 100644 --- a/lib/alfresco/Service/Logger/Logger.php +++ b/lib/alfresco/Service/Logger/Logger.php @@ -1,90 +1,84 @@ -componentName = $componentName; - } - - public function isDebugEnabled() - { - return $this->isEnabled(DEBUG); - } - - public function debug($message) - { - $this->write(DEBUG, $message); - } - - public function isWarningEnabled() - { - return $this->isEnabled(WARNING); - } - - public function warning($message) - { - $this->write(WARNING, $message); - } - - public function isInformationEnabled() - { - return $this->isEnabled(INFORMATION); - } - - public function information($message) - { - $this->write(INFORMATION, $message); - } - - private function isEnabled($logLevel) - { - global $componentLogLevels, $defaultLogLevel; - - $logLevels = $defaultLogLevel; - if ($this->componentName != null && isset($componentLogLevels[$this->componentName]) == true) - { - $logLevels = $componentLogLevels[$this->componentName]; - } - - return in_array($logLevel, $logLevels); - } - - private function write($logLevel, $message) - { - global $logFile; - - $handle = fopen($logFile, "a"); - fwrite($handle, $logLevel." ".date("G:i:s d/m/Y")." - ".$message."\r\n"); - fclose($handle); - } - } -?> +. + */ + + require_once "LoggerConfig.php"; + + class Logger + { + private $componentName; + + public function __construct($componentName = null) + { + $this->componentName = $componentName; + } + + public function isDebugEnabled() + { + return $this->isEnabled(DEBUG); + } + + public function debug($message) + { + $this->write(DEBUG, $message); + } + + public function isWarningEnabled() + { + return $this->isEnabled(WARNING); + } + + public function warning($message) + { + $this->write(WARNING, $message); + } + + public function isInformationEnabled() + { + return $this->isEnabled(INFORMATION); + } + + public function information($message) + { + $this->write(INFORMATION, $message); + } + + private function isEnabled($logLevel) + { + global $componentLogLevels, $defaultLogLevel; + + $logLevels = $defaultLogLevel; + if ($this->componentName != null && isset($componentLogLevels[$this->componentName]) == true) + { + $logLevels = $componentLogLevels[$this->componentName]; + } + + return in_array($logLevel, $logLevels); + } + + private function write($logLevel, $message) + { + global $logFile; + + $handle = fopen($logFile, "a"); + fwrite($handle, $logLevel." ".date("G:i:s d/m/Y")." - ".$message."\r\n"); + fclose($handle); + } + } +?> diff --git a/lib/alfresco/Service/Logger/LoggerConfig.php b/lib/alfresco/Service/Logger/LoggerConfig.php index 4227098da02..d6f010a3849 100644 --- a/lib/alfresco/Service/Logger/LoggerConfig.php +++ b/lib/alfresco/Service/Logger/LoggerConfig.php @@ -1,44 +1,38 @@ - $debugLevel - ); - - -?> +. + */ + +define("DEBUG", "Debug"); +define("WARNING", "Warning"); +define("INFO", "Information"); + +$debugLevel = array(DEBUG, WARNING, INFO); +$warningLevel = array(WARNING, INFO); +$infoLevel = array(INFO); +$noneLevel = array(); + +$defaultLogLevel = $infoLevel; + +$logFile = "c:/work/AlfrescoPHPLog.txt"; +$componentLogLevels = array( + "integration.mediawiki.ExternalStoreAlfresco" => $debugLevel + ); + + +?> diff --git a/lib/alfresco/Service/NamespaceMap.php b/lib/alfresco/Service/NamespaceMap.php index c08ce590b7b..25d880a1b8a 100644 --- a/lib/alfresco/Service/NamespaceMap.php +++ b/lib/alfresco/Service/NamespaceMap.php @@ -1,121 +1,115 @@ - "http://www.alfresco.org/model/dictionary/1.0", - "sys" => "http://www.alfresco.org/model/system/1.0", - "cm" => "http://www.alfresco.org/model/content/1.0", - "app" => "http://www.alfresco.org/model/application/1.0", - "bpm" => "http://www.alfresco.org/model/bpm/1.0", - "wf" => "http://www.alfresco.org/model/workflow/1.0", - "fm" => "http://www.alfresco.org/model/forum/1.0", - "view" => "http://www.alfresco.org/view/repository/1.0", - "security" => "http://www.alfresco.org/model/security/1.0", - "wcm" => "http://www.alfresco.org/model/wcmmodel/1.0", - "wca" => "http://www.alfresco.org/model/wcmappmodel/1.0"); - - public function isShortName($shortName) - { - return ($shortName != $this->getFullName($shortName)); - } - - public function getFullName($shortName) - { - $result = $shortName; - - $index = strpos($shortName, NamespaceMap::DELIMITER); - if ($index !== false) - { - $prefix = substr($shortName, 0, $index); - - if (isset($this->namespaceMap[$prefix]) == true) - { - $url = $this->namespaceMap[$prefix]; - $name = substr($shortName, $index+1); - $name = str_replace("_", "-", $name); - if ($name != null && strlen($name) != 0) - { - $result = "{".$url."}".$name; - } - } - } - - return $result; - } - - public function getFullNames($fullNames) - { - $result = array(); - - foreach ($fullNames as $fullName) - { - $result[] = $this->getFullName($fullName); - } - return $result; - } - - public function getShortName($fullName) - { - $result = $fullName; - - $index = strpos($fullName, "}"); - if ($index !== false) - { - $url = substr($fullName, 1, $index-1); - $prefix = $this->lookupPrefix($url); - if ($prefix != null) - { - $name = substr($fullName, $index+1); - if ($name != null && strlen($name) != 0) - { - $name = str_replace("-", "_", $name); - $result = $prefix.NamespaceMap::DELIMITER.$name; - } - } - } - - return $result; - } - - private function lookupPrefix($value) - { - $result = null; - foreach($this->namespaceMap as $prefix => $url) - { - if ($url == $value) - { - $result = $prefix; - } - } - return $result; - } -} - -?> +. + */ + +class NamespaceMap +{ + const DELIMITER = "_"; + + private $namespaceMap = array( + "d" => "http://www.alfresco.org/model/dictionary/1.0", + "sys" => "http://www.alfresco.org/model/system/1.0", + "cm" => "http://www.alfresco.org/model/content/1.0", + "app" => "http://www.alfresco.org/model/application/1.0", + "bpm" => "http://www.alfresco.org/model/bpm/1.0", + "wf" => "http://www.alfresco.org/model/workflow/1.0", + "fm" => "http://www.alfresco.org/model/forum/1.0", + "view" => "http://www.alfresco.org/view/repository/1.0", + "security" => "http://www.alfresco.org/model/security/1.0", + "wcm" => "http://www.alfresco.org/model/wcmmodel/1.0", + "wca" => "http://www.alfresco.org/model/wcmappmodel/1.0"); + + public function isShortName($shortName) + { + return ($shortName != $this->getFullName($shortName)); + } + + public function getFullName($shortName) + { + $result = $shortName; + + $index = strpos($shortName, NamespaceMap::DELIMITER); + if ($index !== false) + { + $prefix = substr($shortName, 0, $index); + + if (isset($this->namespaceMap[$prefix]) == true) + { + $url = $this->namespaceMap[$prefix]; + $name = substr($shortName, $index+1); + $name = str_replace("_", "-", $name); + if ($name != null && strlen($name) != 0) + { + $result = "{".$url."}".$name; + } + } + } + + return $result; + } + + public function getFullNames($fullNames) + { + $result = array(); + + foreach ($fullNames as $fullName) + { + $result[] = $this->getFullName($fullName); + } + return $result; + } + + public function getShortName($fullName) + { + $result = $fullName; + + $index = strpos($fullName, "}"); + if ($index !== false) + { + $url = substr($fullName, 1, $index-1); + $prefix = $this->lookupPrefix($url); + if ($prefix != null) + { + $name = substr($fullName, $index+1); + if ($name != null && strlen($name) != 0) + { + $name = str_replace("-", "_", $name); + $result = $prefix.NamespaceMap::DELIMITER.$name; + } + } + } + + return $result; + } + + private function lookupPrefix($value) + { + $result = null; + foreach($this->namespaceMap as $prefix => $url) + { + if ($url == $value) + { + $result = $prefix; + } + } + return $result; + } +} + +?> diff --git a/lib/alfresco/Service/Node.php b/lib/alfresco/Service/Node.php index 9fa0fa58b1b..a389dc07b9e 100644 --- a/lib/alfresco/Service/Node.php +++ b/lib/alfresco/Service/Node.php @@ -1,815 +1,809 @@ -_session = $session; - $this->_store = $store; - $this->_id = $id; - $this->_isNewNode = false; - $this->addedChildren = array(); - $this->addedParents = array(); - $this->addedAssociations = array(); - } - - /** - * Util method to create a node from a web service node structure. - */ - public static function createFromWebServiceData($session, $webServiceNode) - { - $scheme = $webServiceNode->reference->store->scheme; - $address = $webServiceNode->reference->store->address; - $id = $webServiceNode->reference->uuid; - - $store = $session->getStore($address, $scheme); - $node = $session->getNode($store, $id); - $node->populateFromWebServiceNode($webServiceNode); - - return $node; - } - - public function setPropertyValues($properties) - { - // Check that the properties of the node have been populated - $this->populateProperties(); - - // Set the property values - foreach ($properties as $name=>$value) - { - $name = $this->_session->namespaceMap->getFullName($name); - $this->_properties[$name] = $value; - } - } - - public function updateContent($property, $mimetype, $encoding="UTF-8", $content=null) - { - list($property) = $this->_session->namespaceMap->getFullNames(array($property)); - $contentData = new ContentData($this, $property, $mimetype, $encoding); - if ($content != null) - { - $contentData->content = $content; - } - $this->_properties[$property] = $contentData; - - return $contentData; - } - - public function hasAspect($aspect) - { - list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); - $this->populateProperties(); - return in_array($aspect, $this->_aspects); - } - - public function addAspect($aspect, $properties = null) - { - list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); - $this->populateProperties(); - - if (in_array($aspect, $this->_aspects) == false) - { - $this->_aspects[] = $aspect; - if ($properties != null) - { - foreach ($properties as $name=>$value) - { - $name = $this->_session->namespaceMap->getFullName($name); - $this->_properties[$name] = $value; - } - } - - $this->remove_array_value($aspect, $this->removedAspects); - $this->addedAspects[] = $aspect; - } - } - - public function removeAspect($aspect) - { - list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); - $this->populateProperties(); - - if (in_array($aspect, $this->_aspects) == true) - { - $this->remove_array_value($aspect, $this->_aspects); - $this->remove_array_value($aspect, $this->addedAspects); - $this->removedAspects[] = $aspect; - } - } - - public function createChild($type, $associationType, $associationName) - { - list($type, $associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($type, $associationType, $associationName)); - - $id = $this->_session->nextSessionId(); - $newNode = new Node($this->_session, $this->_store, $id); - $childAssociation = new ChildAssociation($this, $newNode, $associationType, $associationName, true); - - $newNode->_isNewNode = true; - - $newNode->_properties = array(); - $newNode->_aspects = array(); - $newNode->_properties = array(); - $newNode->_children = array(); - $newNode->origionalProperties = array(); - $newNode->addedAspects = array(); - $newNode->removedAspects = array(); - - $newNode->_type = $type; - $newNode->_parents = array(); - $newNode->addedParents = array($this->__toString() => $childAssociation); - $newNode->_primaryParent = $this; - - $this->addedChildren[$newNode->__toString()] = $childAssociation; - - $this->_session->addNode($newNode); - - return $newNode; - } - - public function addChild($node, $associationType, $associationName) - { - list($associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($associationType, $associationName)); - - $childAssociation = new ChildAssociation($this, $node, $associationType, $associationName, false); - $this->addedChildren[$node->__toString()] = $childAssociation; - $node->addedParents[$this->__toString()] = $childAssociation; - } - - public function removeChild($childAssociation) - { - - } - - public function addAssociation($to, $associationType) - { - list($associationType) = $this->_session->namespaceMap->getFullNames(array($associationType)); - - $association = new Association($this, $to, $associationType); - $this->addedAssociations[$to->__toString()] = $association; - } - - public function removeAssociation($association) - { - - } - - public function createVersion($description=null, $major=false) - { - // We can only create a version if there are no outstanding changes for this node - if ($this->isDirty() == true) - { - throw new Exception("You must save any outstanding modifications before a new version can be created."); - } - - // TODO implement major flag ... - - $client = WebServiceFactory::getAuthoringService($this->_session->repository->connectionUrl, $this->_session->ticket); - $result = $client->createVersion( - array("items" => array("nodes" => $this->__toArray()), - "comments" => array("name" => "description", "value" => $description), - "versionChildren" => false)); - - // Clear the properties and aspects - $this->_properties = null; - $this->_aspects = null; - - // Get the version details - // TODO get some of the other details too ... - $versionId = $result->createVersionReturn->versions->id->uuid; - $versionStoreScheme = $result->createVersionReturn->versions->id->store->scheme; - $versionStoreAddress = $result->createVersionReturn->versions->id->store->address; - - // Create the version object to return - return new Version($this->_session, new Store($this->_session, $versionStoreAddress, $versionStoreScheme), $versionId); - } - - private function isDirty() - { - $result = true; - if ($this->_isNewNode == false && - count($this->getModifiedProperties()) == 0 && - ($this->addedAspects == null || count($this->addedAspects) == 0) && - ($this->removedAssociations == null || count($this->removedAssociations) == 0) && - ($this->addedChildren == null || count($this->addedChildren) == 0) && - ($this->addedAssociations == null || count($this->addedAssociations) == 0)) - { - $result = false; - } - return $result; - } - - public function __get($name) - { - $fullName = $this->_session->namespaceMap->getFullName($name); - if ($fullName != $name) - { - $this->populateProperties(); - if (array_key_exists($fullName, $this->_properties) == true) - { - return $this->_properties[$fullName]; - } - else - { - return null; - } - } - else - { - return parent::__get($name); - } - } - - public function __set($name, $value) - { - $fullName = $this->_session->namespaceMap->getFullName($name); - if ($fullName != $name) - { - $this->populateProperties(); - $this->_properties[$fullName] = $value; - - // Ensure that the node and property details are stored on the contentData object - if ($value instanceof ContentData) - { - $value->setPropertyDetails($this, $fullName); - } - } - else - { - parent::__set($name, $value); - } - } - - /** - * toString method. Returns node as a node reference style string. - */ - public function __toString() - { - return Node::__toNodeRef($this->_store, $this->id); - } - - public static function __toNodeRef($store, $id) - { - return $store->scheme . "://" . $store->address . "/" . $id; - } - - public function __toArray() - { - return array("store" => $this->_store->__toArray(), - "uuid" => $this->_id); - } - - public function getSession() - { - return $this->_session; - } - - public function getStore() - { - return $this->_store; - } - - public function getId() - { - return $this->_id; - } - - public function getIsNewNode() - { - return $this->_isNewNode; - } - - public function getType() - { - $this->populateProperties(); - return $this->_type; - } - - public function getAspects() - { - $this->populateProperties(); - return $this->_aspects; - } - - public function getProperties() - { - $this->populateProperties(); - return $this->_properties; - } - - public function setProperties($properties) - { - $this->populateProperties(); - $this->_properties = $properties; - } - - /** - * Accessor for the versionHistory property. - * - * @return VersionHistory the versionHistory for the node, null is none - */ - public function getVersionHistory() - { - if ($this->_versionHistory == null) - { - $this->_versionHistory = new VersionHistory($this); - } - return $this->_versionHistory; - } - - public function getChildren() - { - if ($this->_children == null) - { - $this->populateChildren(); - } - return $this->_children + $this->addedChildren; - } - - public function getParents() - { - if ($this->_parents == null) - { - $this->populateParents(); - } - return $this->_parents + $this->addedParents; - } - - public function getPrimaryParent() - { - if ($this->_primaryParent == null) - { - $this->populateParents(); - } - return $this->_primaryParent; - } - - public function getAssociations() - { - if ($this->_associations == null) - { - $this->populateAssociations(); - } - return $this->_associations + $this->addedAssociations; - } - - /** Methods used to populate node details from repository */ - - private function populateProperties() - { - if ($this->_isNewNode == false && $this->_properties == null) - { - $result = $this->_session->repositoryService->get(array ( - "where" => array ( - "nodes" => array( - "store" => $this->_store->__toArray(), - "uuid" => $this->_id)))); - - $this->populateFromWebServiceNode($result->getReturn); - } - } - - private function populateFromWebServiceNode($webServiceNode) - { - $this->_type = $webServiceNode->type; - - // Get the aspects - $this->_aspects = array(); - $aspects = $webServiceNode->aspects; - if (is_array($aspects) == true) - { - foreach ($aspects as $aspect) - { - $this->_aspects[] = $aspect; - } - } - else - { - $this->_aspects[] = $aspects; - } - - // Set the property values - // NOTE: do we need to be concerned with identifying whether this is an array or not when there is - // only one property on a node - $this->_properties = array(); - foreach ($webServiceNode->properties as $propertyDetails) - { - $name = $propertyDetails->name; - $isMultiValue = $propertyDetails->isMultiValue; - $value = null; - if ($isMultiValue == false) - { - $value = $propertyDetails->value; - if ($this->isContentData($value) == true) - { - $value = new ContentData($this, $name); - } - } - else - { - $value = $propertyDetails->values; - } - $this->_properties[$name] = $value; - - } - - $this->origionalProperties = $this->_properties; - $this->addedAspects = array(); - $this->removedAspects = array(); - - } - - private function populateChildren() - { - // TODO should do some sort of limited pull here - $result = $this->_session->repositoryService->queryChildren(array("node" => $this->__toArray())); - $resultSet = $result->queryReturn->resultSet; - - $children = array(); - $map = $this->resultSetToMap($resultSet); - foreach($map as $value) - { - $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; - $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; - $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; - $assoc_type = $value["associationType"]; - $assoc_name = $value["associationName"]; - $isPrimary = $value["isPrimary"]; - $nthSibling = $value["nthSibling"]; - - $child = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); - $children[$child->__toString()] = new ChildAssociation($this, $child, $assoc_type, $assoc_name, $isPrimary, $nthSibling); - } - - $this->_children = $children; - } - - private function populateAssociations() - { - // TODO should do some sort of limited pull here - $result = $this->_session->repositoryService->queryAssociated(array("node" => $this->__toArray(), - "association" => array("associationType" => null, - "direction" => null))); - $resultSet = $result->queryReturn->resultSet; - - $associations = array(); - $map = $this->resultSetToMap($resultSet); - foreach($map as $value) - { - $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; - $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; - $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; - $assoc_type = $value["associationType"]; - - $to = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); - $associations[$to->__toString()] = new Association($this, $to, $assoc_type); - } - - $this->_associations = $associations; - } - - private function populateParents() - { - // TODO should do some sort of limited pull here - $result = $this->_session->repositoryService->queryParents(array("node" => $this->__toArray())); - $resultSet = $result->queryReturn->resultSet; - - $parents = array(); - $map = $this->resultSetToMap($resultSet); - foreach($map as $value) - { - $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; - $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; - $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; - $assoc_type = $value["associationType"]; - $assoc_name = $value["associationName"]; - $isPrimary = $value["isPrimary"]; - $nthSibling = $value["nthSibling"]; - - $parent = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); - if ($isPrimary == "true" or $isPrimary == true) - { - $this->_primaryParent = $parent; - } - $parents[$parent->__toString()] = new ChildAssociation($parent, $this, $assoc_type, $assoc_name, $isPrimary, $nthSibling); - } - - $this->_parents = $parents; - } - - public function onBeforeSave(&$statements) - { - if ($this->_isNewNode == true) - { - $childAssociation = $this->addedParents[$this->_primaryParent->__toString()]; - - $parentArray = array(); - $parent = $this->_primaryParent; - if ($parent->_isNewNode == true) - { - $parentArray["parent_id"] = $parent->id; - $parentArray["associationType"] = $childAssociation->type; - $parentArray["childName"] = $childAssociation->name; - } - else - { - $parentArray["parent"] = array( - "store" => $this->_store->__toArray(), - "uuid" => $this->_primaryParent->_id, - "associationType" => $childAssociation->type, - "childName" => $childAssociation->name); - } - - $this->addStatement($statements, "create", - array("id" => $this->_id) + - $parentArray + - array( - "type" => $this->_type, - "property" => $this->getPropertyArray($this->_properties))); - } - else - { - // Add the update statement for the modified properties - $modifiedProperties = $this->getModifiedProperties(); - if (count($modifiedProperties) != 0) - { - $this->addStatement($statements, "update", array("property" => $this->getPropertyArray($modifiedProperties)) + $this->getWhereArray()); - } - - // TODO deal with any deleted properties - } - - // Update any modified content properties - if ($this->_properties != null) - { - foreach($this->_properties as $name=>$value) - { - if (($value instanceof ContentData) && $value->isDirty == true) - { - $value->onBeforeSave($statements, $this->getWhereArray()); - } - } - } - - // Add the addAspect statements - if ($this->addedAspects != null) - { - foreach($this->addedAspects as $aspect) - { - $this->addStatement($statements, "addAspect", array("aspect" => $aspect) + $this->getWhereArray()); - } - } - - // Add the removeAspect - if ($this->removedAspects != null) - { - foreach($this->removedAspects as $aspect) - { - $this->addStatement($statements, "removeAspect", array("aspect" => $aspect) + $this->getWhereArray()); - } - } - - // Add non primary children - foreach($this->addedChildren as $childAssociation) - { - if ($childAssociation->isPrimary == false) - { - - $assocDetails = array("associationType" => $childAssociation->type, "childName" => $childAssociation->name); - - $temp = array(); - if ($childAssociation->child->_isNewNode == true) - { - $temp["to_id"] = $childAssociation->child->_id; - $temp = $temp + $assocDetails; - } - else - { - $temp["to"] = array( - "store" => $this->_store->__toArray(), - "uuid" => $childAssociation->child->_id) + - $assocDetails; - } - $temp = $temp + $this->getWhereArray(); - $this->addStatement($statements, "addChild", $temp); - } - } - - // Add associations - foreach($this->addedAssociations as $association) - { - $temp = array("association" => $association->type); - $temp = $temp + $this->getPredicateArray("from", $this) + $this->getPredicateArray("to", $association->to); - $this->addStatement($statements, "createAssociation", $temp); - } - } - - private function addStatement(&$statements, $statement, $body) - { - $result = array(); - if (array_key_exists($statement, $statements) == true) - { - $result = $statements[$statement]; - } - $result[] = $body; - $statements[$statement] = $result; - } - - private function getWhereArray() - { - return $this->getPredicateArray("where", $this); - } - - private function getPredicateArray($label, $node) - { - if ($node->_isNewNode == true) - { - return array($label."_id" => $node->_id); - } - else - { - return array( - $label => array( - "nodes" => $node->__toArray() - )); - } - } - - private function getPropertyArray($properties) - { - $result = array(); - foreach ($properties as $name=>$value) - { - // Ignore content properties - if (($value instanceof ContentData) == false) - { - // TODO need to support multi values - $result[] = array( - "name" => $name, - "isMultiValue" => false, - "value" => $value); - } - } - return $result; - } - - private function getModifiedProperties() - { - $modified = $this->_properties; - $origional = $this->origionalProperties; - $result = array(); - if ($modified != null) - { - foreach ($modified as $key=>$value) - { - // Ignore content properties - if (($value instanceof ContentData) == false) - { - if (array_key_exists($key, $origional) == true) - { - // Check to see if the value have been modified - if ($value != $origional[$key]) - { - $result[$key] = $value; - } - } - else - { - $result[$key] = $value; - } - } - } - } - return $result; - } - - public function onAfterSave($idMap) - { - if (array_key_exists($this->_id, $idMap ) == true) - { - $uuid = $idMap[$this->_id]; - if ($uuid != null) - { - $this->_id = $uuid; - } - } - - if ($this->_isNewNode == true) - { - $this->_isNewNode = false; - - // Clear the properties and aspect - $this->_properties = null; - $this->_aspects = null; - } - - // Update any modified content properties - if ($this->_properties != null) - { - foreach($this->_properties as $name=>$value) - { - if (($value instanceof ContentData) && $value->isDirty == true) - { - $value->onAfterSave(); - } - } - } - - $this->origionalProperties = $this->_properties; - - if ($this->_aspects != null) - { - // Calculate the updated aspect list - if ($this->addedAspects != null) - { - $this->_aspects = $this->_aspects + $this->addedAspects; - } - if ($this->removedAspects != null) - { - foreach ($this->_aspects as $aspect) - { - if (in_array($aspect, $this->removedAspects) == true) - { - $this->remove_array_value($aspect, $this->_aspects); - } - } - } - } - $this->addedAspects = array(); - $this->removedAspects = array(); - - if ($this->_parents != null) - { - $this->_parents = $this->_parents + $this->addedParents; - } - $this->addedParents = array(); - - if ($this->_children != null) - { - $this->_children = $this->_children + $this->addedChildren; - } - $this->addedChildren = array(); - - if ($this->_associations != null) - { - $this->_associations = $this->_associations + $this->addedAssociations; - } - $this->addedAssociations = array(); - } -} +. + */ + +require_once 'Store.php'; +require_once 'ChildAssociation.php'; +require_once 'Association.php'; +require_once 'NamespaceMap.php'; +require_once 'ContentData.php'; +require_once 'VersionHistory.php'; +require_once 'Version.php'; + +class Node extends BaseObject +{ + private $_session; + private $_store; + private $_id; + private $_type; + private $_aspects; + private $_properties; + private $_children; + private $_parents; + private $_primaryParent; + private $_isNewNode; + private $_associations; + private $_versionHistory; + private $origionalProperties; + private $addedAspects; + private $removedAspects; + private $addedChildren; + private $addedParents; + private $addedAssociations; + private $removedAssociations; + + /** + * Constructor + */ + public function __construct($session, $store, $id) + { + $this->_session = $session; + $this->_store = $store; + $this->_id = $id; + $this->_isNewNode = false; + $this->addedChildren = array(); + $this->addedParents = array(); + $this->addedAssociations = array(); + } + + /** + * Util method to create a node from a web service node structure. + */ + public static function createFromWebServiceData($session, $webServiceNode) + { + $scheme = $webServiceNode->reference->store->scheme; + $address = $webServiceNode->reference->store->address; + $id = $webServiceNode->reference->uuid; + + $store = $session->getStore($address, $scheme); + $node = $session->getNode($store, $id); + $node->populateFromWebServiceNode($webServiceNode); + + return $node; + } + + public function setPropertyValues($properties) + { + // Check that the properties of the node have been populated + $this->populateProperties(); + + // Set the property values + foreach ($properties as $name=>$value) + { + $name = $this->_session->namespaceMap->getFullName($name); + $this->_properties[$name] = $value; + } + } + + public function updateContent($property, $mimetype, $encoding="UTF-8", $content=null) + { + list($property) = $this->_session->namespaceMap->getFullNames(array($property)); + $contentData = new ContentData($this, $property, $mimetype, $encoding); + if ($content != null) + { + $contentData->content = $content; + } + $this->_properties[$property] = $contentData; + + return $contentData; + } + + public function hasAspect($aspect) + { + list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); + $this->populateProperties(); + return in_array($aspect, $this->_aspects); + } + + public function addAspect($aspect, $properties = null) + { + list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); + $this->populateProperties(); + + if (in_array($aspect, $this->_aspects) == false) + { + $this->_aspects[] = $aspect; + if ($properties != null) + { + foreach ($properties as $name=>$value) + { + $name = $this->_session->namespaceMap->getFullName($name); + $this->_properties[$name] = $value; + } + } + + $this->remove_array_value($aspect, $this->removedAspects); + $this->addedAspects[] = $aspect; + } + } + + public function removeAspect($aspect) + { + list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect)); + $this->populateProperties(); + + if (in_array($aspect, $this->_aspects) == true) + { + $this->remove_array_value($aspect, $this->_aspects); + $this->remove_array_value($aspect, $this->addedAspects); + $this->removedAspects[] = $aspect; + } + } + + public function createChild($type, $associationType, $associationName) + { + list($type, $associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($type, $associationType, $associationName)); + + $id = $this->_session->nextSessionId(); + $newNode = new Node($this->_session, $this->_store, $id); + $childAssociation = new ChildAssociation($this, $newNode, $associationType, $associationName, true); + + $newNode->_isNewNode = true; + + $newNode->_properties = array(); + $newNode->_aspects = array(); + $newNode->_properties = array(); + $newNode->_children = array(); + $newNode->origionalProperties = array(); + $newNode->addedAspects = array(); + $newNode->removedAspects = array(); + + $newNode->_type = $type; + $newNode->_parents = array(); + $newNode->addedParents = array($this->__toString() => $childAssociation); + $newNode->_primaryParent = $this; + + $this->addedChildren[$newNode->__toString()] = $childAssociation; + + $this->_session->addNode($newNode); + + return $newNode; + } + + public function addChild($node, $associationType, $associationName) + { + list($associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($associationType, $associationName)); + + $childAssociation = new ChildAssociation($this, $node, $associationType, $associationName, false); + $this->addedChildren[$node->__toString()] = $childAssociation; + $node->addedParents[$this->__toString()] = $childAssociation; + } + + public function removeChild($childAssociation) + { + + } + + public function addAssociation($to, $associationType) + { + list($associationType) = $this->_session->namespaceMap->getFullNames(array($associationType)); + + $association = new Association($this, $to, $associationType); + $this->addedAssociations[$to->__toString()] = $association; + } + + public function removeAssociation($association) + { + + } + + public function createVersion($description=null, $major=false) + { + // We can only create a version if there are no outstanding changes for this node + if ($this->isDirty() == true) + { + throw new Exception("You must save any outstanding modifications before a new version can be created."); + } + + // TODO implement major flag ... + + $client = WebServiceFactory::getAuthoringService($this->_session->repository->connectionUrl, $this->_session->ticket); + $result = $client->createVersion( + array("items" => array("nodes" => $this->__toArray()), + "comments" => array("name" => "description", "value" => $description), + "versionChildren" => false)); + + // Clear the properties and aspects + $this->_properties = null; + $this->_aspects = null; + + // Get the version details + // TODO get some of the other details too ... + $versionId = $result->createVersionReturn->versions->id->uuid; + $versionStoreScheme = $result->createVersionReturn->versions->id->store->scheme; + $versionStoreAddress = $result->createVersionReturn->versions->id->store->address; + + // Create the version object to return + return new Version($this->_session, new Store($this->_session, $versionStoreAddress, $versionStoreScheme), $versionId); + } + + private function isDirty() + { + $result = true; + if ($this->_isNewNode == false && + count($this->getModifiedProperties()) == 0 && + ($this->addedAspects == null || count($this->addedAspects) == 0) && + ($this->removedAssociations == null || count($this->removedAssociations) == 0) && + ($this->addedChildren == null || count($this->addedChildren) == 0) && + ($this->addedAssociations == null || count($this->addedAssociations) == 0)) + { + $result = false; + } + return $result; + } + + public function __get($name) + { + $fullName = $this->_session->namespaceMap->getFullName($name); + if ($fullName != $name) + { + $this->populateProperties(); + if (array_key_exists($fullName, $this->_properties) == true) + { + return $this->_properties[$fullName]; + } + else + { + return null; + } + } + else + { + return parent::__get($name); + } + } + + public function __set($name, $value) + { + $fullName = $this->_session->namespaceMap->getFullName($name); + if ($fullName != $name) + { + $this->populateProperties(); + $this->_properties[$fullName] = $value; + + // Ensure that the node and property details are stored on the contentData object + if ($value instanceof ContentData) + { + $value->setPropertyDetails($this, $fullName); + } + } + else + { + parent::__set($name, $value); + } + } + + /** + * toString method. Returns node as a node reference style string. + */ + public function __toString() + { + return Node::__toNodeRef($this->_store, $this->id); + } + + public static function __toNodeRef($store, $id) + { + return $store->scheme . "://" . $store->address . "/" . $id; + } + + public function __toArray() + { + return array("store" => $this->_store->__toArray(), + "uuid" => $this->_id); + } + + public function getSession() + { + return $this->_session; + } + + public function getStore() + { + return $this->_store; + } + + public function getId() + { + return $this->_id; + } + + public function getIsNewNode() + { + return $this->_isNewNode; + } + + public function getType() + { + $this->populateProperties(); + return $this->_type; + } + + public function getAspects() + { + $this->populateProperties(); + return $this->_aspects; + } + + public function getProperties() + { + $this->populateProperties(); + return $this->_properties; + } + + public function setProperties($properties) + { + $this->populateProperties(); + $this->_properties = $properties; + } + + /** + * Accessor for the versionHistory property. + * + * @return VersionHistory the versionHistory for the node, null is none + */ + public function getVersionHistory() + { + if ($this->_versionHistory == null) + { + $this->_versionHistory = new VersionHistory($this); + } + return $this->_versionHistory; + } + + public function getChildren() + { + if ($this->_children == null) + { + $this->populateChildren(); + } + return $this->_children + $this->addedChildren; + } + + public function getParents() + { + if ($this->_parents == null) + { + $this->populateParents(); + } + return $this->_parents + $this->addedParents; + } + + public function getPrimaryParent() + { + if ($this->_primaryParent == null) + { + $this->populateParents(); + } + return $this->_primaryParent; + } + + public function getAssociations() + { + if ($this->_associations == null) + { + $this->populateAssociations(); + } + return $this->_associations + $this->addedAssociations; + } + + /** Methods used to populate node details from repository */ + + private function populateProperties() + { + if ($this->_isNewNode == false && $this->_properties == null) + { + $result = $this->_session->repositoryService->get(array ( + "where" => array ( + "nodes" => array( + "store" => $this->_store->__toArray(), + "uuid" => $this->_id)))); + + $this->populateFromWebServiceNode($result->getReturn); + } + } + + private function populateFromWebServiceNode($webServiceNode) + { + $this->_type = $webServiceNode->type; + + // Get the aspects + $this->_aspects = array(); + $aspects = $webServiceNode->aspects; + if (is_array($aspects) == true) + { + foreach ($aspects as $aspect) + { + $this->_aspects[] = $aspect; + } + } + else + { + $this->_aspects[] = $aspects; + } + + // Set the property values + // NOTE: do we need to be concerned with identifying whether this is an array or not when there is + // only one property on a node + $this->_properties = array(); + foreach ($webServiceNode->properties as $propertyDetails) + { + $name = $propertyDetails->name; + $isMultiValue = $propertyDetails->isMultiValue; + $value = null; + if ($isMultiValue == false) + { + $value = $propertyDetails->value; + if ($this->isContentData($value) == true) + { + $value = new ContentData($this, $name); + } + } + else + { + $value = $propertyDetails->value; + } + $this->_properties[$name] = $value; + + } + + $this->origionalProperties = $this->_properties; + $this->addedAspects = array(); + $this->removedAspects = array(); + + } + + private function populateChildren() + { + // TODO should do some sort of limited pull here + $result = $this->_session->repositoryService->queryChildren(array("node" => $this->__toArray())); + $resultSet = $result->queryReturn->resultSet; + + $children = array(); + $map = $this->resultSetToMap($resultSet); + foreach($map as $value) + { + $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; + $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; + $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; + $assoc_type = $value["associationType"]; + $assoc_name = $value["associationName"]; + $isPrimary = $value["isPrimary"]; + $nthSibling = $value["nthSibling"]; + + $child = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); + $children[$child->__toString()] = new ChildAssociation($this, $child, $assoc_type, $assoc_name, $isPrimary, $nthSibling); + } + + $this->_children = $children; + } + + private function populateAssociations() + { + // TODO should do some sort of limited pull here + $result = $this->_session->repositoryService->queryAssociated(array("node" => $this->__toArray(), + "association" => array("associationType" => null, + "direction" => null))); + $resultSet = $result->queryReturn->resultSet; + + $associations = array(); + $map = $this->resultSetToMap($resultSet); + foreach($map as $value) + { + $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; + $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; + $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; + $assoc_type = $value["associationType"]; + + $to = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); + $associations[$to->__toString()] = new Association($this, $to, $assoc_type); + } + + $this->_associations = $associations; + } + + private function populateParents() + { + // TODO should do some sort of limited pull here + $result = $this->_session->repositoryService->queryParents(array("node" => $this->__toArray())); + $resultSet = $result->queryReturn->resultSet; + + $parents = array(); + $map = $this->resultSetToMap($resultSet); + foreach($map as $value) + { + $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"]; + $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"]; + $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"]; + $assoc_type = $value["associationType"]; + $assoc_name = $value["associationName"]; + $isPrimary = $value["isPrimary"]; + $nthSibling = $value["nthSibling"]; + + $parent = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id); + if ($isPrimary == "true" or $isPrimary == true) + { + $this->_primaryParent = $parent; + } + $parents[$parent->__toString()] = new ChildAssociation($parent, $this, $assoc_type, $assoc_name, $isPrimary, $nthSibling); + } + + $this->_parents = $parents; + } + + public function onBeforeSave(&$statements) + { + if ($this->_isNewNode == true) + { + $childAssociation = $this->addedParents[$this->_primaryParent->__toString()]; + + $parentArray = array(); + $parent = $this->_primaryParent; + if ($parent->_isNewNode == true) + { + $parentArray["parent_id"] = $parent->id; + $parentArray["associationType"] = $childAssociation->type; + $parentArray["childName"] = $childAssociation->name; + } + else + { + $parentArray["parent"] = array( + "store" => $this->_store->__toArray(), + "uuid" => $this->_primaryParent->_id, + "associationType" => $childAssociation->type, + "childName" => $childAssociation->name); + } + + $this->addStatement($statements, "create", + array("id" => $this->_id) + + $parentArray + + array( + "type" => $this->_type, + "property" => $this->getPropertyArray($this->_properties))); + } + else + { + // Add the update statement for the modified properties + $modifiedProperties = $this->getModifiedProperties(); + if (count($modifiedProperties) != 0) + { + $this->addStatement($statements, "update", array("property" => $this->getPropertyArray($modifiedProperties)) + $this->getWhereArray()); + } + + // TODO deal with any deleted properties + } + + // Update any modified content properties + if ($this->_properties != null) + { + foreach($this->_properties as $name=>$value) + { + if (($value instanceof ContentData) && $value->isDirty == true) + { + $value->onBeforeSave($statements, $this->getWhereArray()); + } + } + } + + // Add the addAspect statements + if ($this->addedAspects != null) + { + foreach($this->addedAspects as $aspect) + { + $this->addStatement($statements, "addAspect", array("aspect" => $aspect) + $this->getWhereArray()); + } + } + + // Add the removeAspect + if ($this->removedAspects != null) + { + foreach($this->removedAspects as $aspect) + { + $this->addStatement($statements, "removeAspect", array("aspect" => $aspect) + $this->getWhereArray()); + } + } + + // Add non primary children + foreach($this->addedChildren as $childAssociation) + { + if ($childAssociation->isPrimary == false) + { + + $assocDetails = array("associationType" => $childAssociation->type, "childName" => $childAssociation->name); + + $temp = array(); + if ($childAssociation->child->_isNewNode == true) + { + $temp["to_id"] = $childAssociation->child->_id; + $temp = $temp + $assocDetails; + } + else + { + $temp["to"] = array( + "store" => $this->_store->__toArray(), + "uuid" => $childAssociation->child->_id) + + $assocDetails; + } + $temp = $temp + $this->getWhereArray(); + $this->addStatement($statements, "addChild", $temp); + } + } + + // Add associations + foreach($this->addedAssociations as $association) + { + $temp = array("association" => $association->type); + $temp = $temp + $this->getPredicateArray("from", $this) + $this->getPredicateArray("to", $association->to); + $this->addStatement($statements, "createAssociation", $temp); + } + } + + private function addStatement(&$statements, $statement, $body) + { + $result = array(); + if (array_key_exists($statement, $statements) == true) + { + $result = $statements[$statement]; + } + $result[] = $body; + $statements[$statement] = $result; + } + + private function getWhereArray() + { + return $this->getPredicateArray("where", $this); + } + + private function getPredicateArray($label, $node) + { + if ($node->_isNewNode == true) + { + return array($label."_id" => $node->_id); + } + else + { + return array( + $label => array( + "nodes" => $node->__toArray() + )); + } + } + + private function getPropertyArray($properties) + { + $result = array(); + foreach ($properties as $name=>$value) + { + // Ignore content properties + if (($value instanceof ContentData) == false) + { + // TODO need to support multi values + $result[] = array( + "name" => $name, + "isMultiValue" => false, + "value" => $value); + } + } + return $result; + } + + private function getModifiedProperties() + { + $modified = $this->_properties; + $origional = $this->origionalProperties; + $result = array(); + if ($modified != null) + { + foreach ($modified as $key=>$value) + { + // Ignore content properties + if (($value instanceof ContentData) == false) + { + if (array_key_exists($key, $origional) == true) + { + // Check to see if the value have been modified + if ($value != $origional[$key]) + { + $result[$key] = $value; + } + } + else + { + $result[$key] = $value; + } + } + } + } + return $result; + } + + public function onAfterSave($idMap) + { + if (array_key_exists($this->_id, $idMap ) == true) + { + $uuid = $idMap[$this->_id]; + if ($uuid != null) + { + $this->_id = $uuid; + } + } + + if ($this->_isNewNode == true) + { + $this->_isNewNode = false; + + // Clear the properties and aspect + $this->_properties = null; + $this->_aspects = null; + } + + // Update any modified content properties + if ($this->_properties != null) + { + foreach($this->_properties as $name=>$value) + { + if (($value instanceof ContentData) && $value->isDirty == true) + { + $value->onAfterSave(); + } + } + } + + $this->origionalProperties = $this->_properties; + + if ($this->_aspects != null) + { + // Calculate the updated aspect list + if ($this->addedAspects != null) + { + $this->_aspects = $this->_aspects + $this->addedAspects; + } + if ($this->removedAspects != null) + { + foreach ($this->_aspects as $aspect) + { + if (in_array($aspect, $this->removedAspects) == true) + { + $this->remove_array_value($aspect, $this->_aspects); + } + } + } + } + $this->addedAspects = array(); + $this->removedAspects = array(); + + if ($this->_parents != null) + { + $this->_parents = $this->_parents + $this->addedParents; + } + $this->addedParents = array(); + + if ($this->_children != null) + { + $this->_children = $this->_children + $this->addedChildren; + } + $this->addedChildren = array(); + + if ($this->_associations != null) + { + $this->_associations = $this->_associations + $this->addedAssociations; + } + $this->addedAssociations = array(); + } +} ?> \ No newline at end of file diff --git a/lib/alfresco/Service/Repository.php b/lib/alfresco/Service/Repository.php index 6d1796728bd..9ac38f6c42b 100644 --- a/lib/alfresco/Service/Repository.php +++ b/lib/alfresco/Service/Repository.php @@ -1,139 +1,127 @@ -libdir.'/alfresco/Service/WebService/WebServiceFactory.php'; -require_once $CFG->libdir.'/alfresco/Service/BaseObject.php'; - -if (isset($_SESSION) == false) -{ - // Start the session - session_start(); -} - -// change by moodle -class Alfresco_Repository extends BaseObject -{ - private $_connectionUrl; - private $_host; - private $_port; - - public function __construct($connectionUrl="http://localhost:8080/alfresco/api") - { - $this->_connectionUrl = $connectionUrl; - $parts = parse_url($connectionUrl); - $this->_host = $parts["host"]; - if (empty($parts["port"])) { - $this->_port = 80; - } else { - $this->_port = $parts["port"]; - } - } - - public function getConnectionUrl() - { - return $this->_connectionUrl; - } - - public function getHost() - { - return $this->_host; - } - - public function getPort() - { - return $this->_port; - } - - public function authenticate($userName, $password) - { - // TODO need to handle exceptions! - - $authenticationService = WebServiceFactory::getAuthenticationService($this->_connectionUrl); - $result = $authenticationService->startSession(array ( - "username" => $userName, - "password" => $password - )); - - // Get the ticket and sessionId - $ticket = $result->startSessionReturn->ticket; - $sessionId = $result->startSessionReturn->sessionid; - - // Store the session id for later use - if ($sessionId != null) - { - $sessionIds = null; - if (isset($_SESSION["sessionIds"]) == false) - { - $sessionIds = array(); - } - else - { - $sessionIds = $_SESSION["sessionIds"]; - } - $sessionIds[$ticket] = $sessionId; - $_SESSION["sessionIds"] = $sessionIds; - } - - return $ticket; - } - - public function createSession($ticket=null) - { - $session = null; - - if ($ticket == null) - { - // TODO get ticket from some well known location ie: the $_SESSION - } - else - { - // TODO would be nice to be able to check that the ticket is still valid! - - // Create new session - $session = new Session($this, $ticket); - } - - return $session; - } - - /** - * For a given ticket, returns the realated session id, null if one can not be found. - */ - public static function getSessionId($ticket) - { - $result = null; - if (isset($_SESSION["sessionIds"]) == true) - { - $result = $_SESSION["sessionIds"][$ticket]; - } - return $result; - - } - -} - - ?> +. + */ + +require_once 'Alfresco/Service/WebService/WebServiceFactory.php'; +require_once 'Alfresco/Service/BaseObject.php'; + +if (isset($_SESSION) == false) +{ + // Start the session + session_start(); +} + +class Repository extends BaseObject +{ + private $_connectionUrl; + private $_host; + private $_port; + + public function __construct($connectionUrl="http://localhost:8080/alfresco/api") + { + $this->_connectionUrl = $connectionUrl; + $parts = parse_url($connectionUrl); + $this->_host = $parts["host"]; + $this->_port = $parts["port"]; + } + + public function getConnectionUrl() + { + return $this->_connectionUrl; + } + + public function getHost() + { + return $this->_host; + } + + public function getPort() + { + return $this->_port; + } + + public function authenticate($userName, $password) + { + // TODO need to handle exceptions! + + $authenticationService = WebServiceFactory::getAuthenticationService($this->_connectionUrl); + $result = $authenticationService->startSession(array ( + "username" => $userName, + "password" => $password + )); + + // Get the ticket and sessionId + $ticket = $result->startSessionReturn->ticket; + $sessionId = $result->startSessionReturn->sessionid; + + // Store the session id for later use + if ($sessionId != null) + { + $sessionIds = null; + if (isset($_SESSION["sessionIds"]) == false) + { + $sessionIds = array(); + } + else + { + $sessionIds = $_SESSION["sessionIds"]; + } + $sessionIds[$ticket] = $sessionId; + $_SESSION["sessionIds"] = $sessionIds; + } + + return $ticket; + } + + public function createSession($ticket=null) + { + $session = null; + + if ($ticket == null) + { + // TODO get ticket from some well known location ie: the $_SESSION + } + else + { + // TODO would be nice to be able to check that the ticket is still valid! + + // Create new session + $session = new Session($this, $ticket); + } + + return $session; + } + + /** + * For a given ticket, returns the realated session id, null if one can not be found. + */ + public static function getSessionId($ticket) + { + $result = null; + if (isset($_SESSION["sessionIds"]) == true) + { + $result = $_SESSION["sessionIds"][$ticket]; + } + return $result; + + } + +} + + ?> \ No newline at end of file diff --git a/lib/alfresco/Service/Session.php b/lib/alfresco/Service/Session.php index 880eaa5324e..85d5ac81226 100644 --- a/lib/alfresco/Service/Session.php +++ b/lib/alfresco/Service/Session.php @@ -1,277 +1,271 @@ -nodeCache = array(); - - $this->_repository = $repository; - $this->_ticket = $ticket; - - $this->repositoryService = WebServiceFactory::getRepositoryService($this->_repository->connectionUrl, $this->_ticket); - $this->contentService = WebServiceFactory::getContentService($this->_repository->connectionUrl, $this->_ticket); - } - - /** - * Creates a new store in the current respository - * - * @param $address the address of the new store - * @param $scheme the scheme of the new store, default value of 'workspace' - * @return Store the new store - */ - public function createStore($address, $scheme="workspace") - { - // Create the store - $result = $this->repositoryService->createStore(array( - "scheme" => $scheme, - "address" => $address)); - $store = new Store($this, $result->createStoreReturn->address, $result->createStoreReturn->scheme); - - // Add to the cached list if its been populated - if (isset($this->_stores) == true) - { - $this->_stores[] = $store; - } - - // Return the newly created store - return $store; - } - - /** - * Get the store - * - * @param $address the address of the store - * @param $scheme the scheme of the store. The default it 'workspace' - * @return Store the store - */ - public function getStore($address, $scheme="workspace") - { - return new Store($this, $address, $scheme); - } - - /** - * Get the store from it string representation (eg: workspace://SpacesStore) - * - * @param $value the stores string representation - * @return Store the store - */ - public function getStoreFromString($value) - { - list($scheme, $address) = explode("://", $value); - return new Store($this, $address, $scheme); - } - - public function getNode($store, $id) - { - $node = $this->getNodeImpl($store, $id); - if ($node == null) - { - $node = new Node($this, $store, $id); - $this->addNode($node); - } - return $node; - } - - public function getNodeFromString($value) - { - // TODO - throw new Exception("getNode($value) not yet implemented"); - } - - /** - * Adds a new node to the session. - */ - public function addNode($node) - { - $this->nodeCache[$node->__toString()] = $node; - } - - private function getNodeImpl($store, $id) - { - $result = null; - $nodeRef = $store->scheme . "://" . $store->address . "/" . $id; - if (array_key_exists($nodeRef, $this->nodeCache) == true) - { - $result = $this->nodeCache[$nodeRef]; - } - return $result; - } - - /** - * Commits all unsaved changes to the repository - */ - public function save($debug=false) - { - // Build the update statements from the node cache - $statements = array(); - foreach ($this->nodeCache as $node) - { - $node->onBeforeSave($statements); - } - - if ($debug == true) - { - var_dump($statements); - echo ("

"); - } - - if (count($statements) > 0) - { - // Make the web service call - $result = $this->repositoryService->update(array("statements" => $statements)); - //var_dump($result); - - // Update the state of the updated nodes - foreach ($this->nodeCache as $node) - { - $node->onAfterSave($this->getIdMap($result)); - } - } - } - - /** - * Clears the current session by emptying the node cache. - * - * WARNING: all unsaved changes will be lost when clearing the session. - */ - public function clear() - { - // Clear the node cache - $this->nodeCache = array(); - } - - private function getIdMap($result) - { - $return = array(); - $statements = $result->updateReturn; - if (is_array($statements) == true) - { - foreach ($statements as $statement) - { - if ($statement->statement == "create") - { - $id = $statement->sourceId; - $uuid = $statement->destination->uuid; - $return[$id] = $uuid; - } - } - } - else - { - if ($statements->statement == "create") - { - $id = $statements->sourceId; - $uuid = $statements->destination->uuid; - $return[$id] = $uuid; - } - } - return $return; - } - - public function query($store, $query, $language='lucene') - { - // TODO need to support paged queries - $result = $this->repositoryService->query(array( - "store" => $store->__toArray(), - "query" => array( - "language" => $language, - "statement" => $query), - "includeMetaData" => false)); - - // TODO for now do nothing with the score and the returned data - $resultSet = $result->queryReturn->resultSet; - return $this->resultSetToNodes($this, $store, $resultSet); - } - - public function getTicket() - { - return $this->_ticket; - } - - public function getRepository() - { - return $this->_repository; - } - - public function getNamespaceMap() - { - if ($this->_namespaceMap == null) - { - $this->_namespaceMap = new NamespaceMap(); - } - return $this->_namespaceMap; - } - - public function getStores() - { - if (isset ($this->_stores) == false) - { - $this->_stores = array (); - $results = $this->repositoryService->getStores(); - - foreach ($results->getStoresReturn as $result) - { - $this->_stores[] = new Store($this, $result->address, $result->scheme); - } - } - - return $this->_stores; - } - - /** Want these methods to be package scope some how! **/ - - public function nextSessionId() - { - $sessionId = "session".$this->_ticket.$this->idCount; - $this->idCount ++; - return $sessionId; - } -} -?> +. + */ + +require_once 'Store.php'; +require_once 'Node.php'; +require_once 'WebService/WebServiceFactory.php'; + +class Session extends BaseObject +{ + public $authenticationService; + public $repositoryService; + public $contentService; + + private $_repository; + private $_ticket; + private $_stores; + private $_namespaceMap; + + private $nodeCache; + private $idCount = 0; + + /** + * Constructor + * + * @param userName the user name + * @param ticket the currenlty authenticated users ticket + */ + public function __construct($repository, $ticket) + { + $this->nodeCache = array(); + + $this->_repository = $repository; + $this->_ticket = $ticket; + + $this->repositoryService = WebServiceFactory::getRepositoryService($this->_repository->connectionUrl, $this->_ticket); + $this->contentService = WebServiceFactory::getContentService($this->_repository->connectionUrl, $this->_ticket); + } + + /** + * Creates a new store in the current respository + * + * @param $address the address of the new store + * @param $scheme the scheme of the new store, default value of 'workspace' + * @return Store the new store + */ + public function createStore($address, $scheme="workspace") + { + // Create the store + $result = $this->repositoryService->createStore(array( + "scheme" => $scheme, + "address" => $address)); + $store = new Store($this, $result->createStoreReturn->address, $result->createStoreReturn->scheme); + + // Add to the cached list if its been populated + if (isset($this->_stores) == true) + { + $this->_stores[] = $store; + } + + // Return the newly created store + return $store; + } + + /** + * Get the store + * + * @param $address the address of the store + * @param $scheme the scheme of the store. The default it 'workspace' + * @return Store the store + */ + public function getStore($address, $scheme="workspace") + { + return new Store($this, $address, $scheme); + } + + /** + * Get the store from it string representation (eg: workspace://SpacesStore) + * + * @param $value the stores string representation + * @return Store the store + */ + public function getStoreFromString($value) + { + list($scheme, $address) = split("://", $value); + return new Store($this, $address, $scheme); + } + + public function getNode($store, $id) + { + $node = $this->getNodeImpl($store, $id); + if ($node == null) + { + $node = new Node($this, $store, $id); + $this->addNode($node); + } + return $node; + } + + public function getNodeFromString($value) + { + // TODO + throw new Exception("getNode($value) not yet implemented"); + } + + /** + * Adds a new node to the session. + */ + public function addNode($node) + { + $this->nodeCache[$node->__toString()] = $node; + } + + private function getNodeImpl($store, $id) + { + $result = null; + $nodeRef = $store->scheme . "://" . $store->address . "/" . $id; + if (array_key_exists($nodeRef, $this->nodeCache) == true) + { + $result = $this->nodeCache[$nodeRef]; + } + return $result; + } + + /** + * Commits all unsaved changes to the repository + */ + public function save($debug=false) + { + // Build the update statements from the node cache + $statements = array(); + foreach ($this->nodeCache as $node) + { + $node->onBeforeSave($statements); + } + + if ($debug == true) + { + var_dump($statements); + echo ("

"); + } + + if (count($statements) > 0) + { + // Make the web service call + $result = $this->repositoryService->update(array("statements" => $statements)); + //var_dump($result); + + // Update the state of the updated nodes + foreach ($this->nodeCache as $node) + { + $node->onAfterSave($this->getIdMap($result)); + } + } + } + + /** + * Clears the current session by emptying the node cache. + * + * WARNING: all unsaved changes will be lost when clearing the session. + */ + public function clear() + { + // Clear the node cache + $this->nodeCache = array(); + } + + private function getIdMap($result) + { + $return = array(); + $statements = $result->updateReturn; + if (is_array($statements) == true) + { + foreach ($statements as $statement) + { + if ($statement->statement == "create") + { + $id = $statement->sourceId; + $uuid = $statement->destination->uuid; + $return[$id] = $uuid; + } + } + } + else + { + if ($statements->statement == "create") + { + $id = $statements->sourceId; + $uuid = $statements->destination->uuid; + $return[$id] = $uuid; + } + } + return $return; + } + + public function query($store, $query, $language='lucene') + { + // TODO need to support paged queries + $result = $this->repositoryService->query(array( + "store" => $store->__toArray(), + "query" => array( + "language" => $language, + "statement" => $query), + "includeMetaData" => false)); + + // TODO for now do nothing with the score and the returned data + $resultSet = $result->queryReturn->resultSet; + return $this->resultSetToNodes($this, $store, $resultSet); + } + + public function getTicket() + { + return $this->_ticket; + } + + public function getRepository() + { + return $this->_repository; + } + + public function getNamespaceMap() + { + if ($this->_namespaceMap == null) + { + $this->_namespaceMap = new NamespaceMap(); + } + return $this->_namespaceMap; + } + + public function getStores() + { + if (isset ($this->_stores) == false) + { + $this->_stores = array (); + $results = $this->repositoryService->getStores(); + + foreach ($results->getStoresReturn as $result) + { + $this->_stores[] = new Store($this, $result->address, $result->scheme); + } + } + + return $this->_stores; + } + + /** Want these methods to be package scope some how! **/ + + public function nextSessionId() + { + $sessionId = "session".$this->_ticket.$this->idCount; + $this->idCount ++; + return $sessionId; + } +} +?> \ No newline at end of file diff --git a/lib/alfresco/Service/SpacesStore.php b/lib/alfresco/Service/SpacesStore.php index 91082c44765..92fc90b23d1 100644 --- a/lib/alfresco/Service/SpacesStore.php +++ b/lib/alfresco/Service/SpacesStore.php @@ -1,54 +1,48 @@ -scheme . "://" . $this->address; - } - - public function getCompanyHome() - { - if ($this->_companyHome == null) - { - $nodes = $this->_session->query($this, 'PATH:"app:company_home"'); - $this->_companyHome = $nodes[0]; - } - return $this->_companyHome; - } -} +. + */ + +require_once 'Store.php'; +require_once 'Node.php'; + +class SpacesStore extends Store +{ + private $_companyHome; + + public function __construct($session) + { + parent::__construct($session, "SpacesStore"); + } + + public function __toString() + { + return $this->scheme . "://" . $this->address; + } + + public function getCompanyHome() + { + if ($this->_companyHome == null) + { + $nodes = $this->_session->query($this, 'PATH:"app:company_home"'); + $this->_companyHome = $nodes[0]; + } + return $this->_companyHome; + } +} ?> \ No newline at end of file diff --git a/lib/alfresco/Service/Store.php b/lib/alfresco/Service/Store.php index 723ca9ccc05..3f2f8647daf 100644 --- a/lib/alfresco/Service/Store.php +++ b/lib/alfresco/Service/Store.php @@ -1,81 +1,75 @@ -_session = $session; - $this->_address = $address; - $this->_scheme = $scheme; - } - - public function __toString() - { - return $this->scheme . "://" . $this->address; - } - - public function __toArray() - { - return array( - "scheme" => $this->_scheme, - "address" => $this->_address); - } - - public function getAddress() - { - return $this->_address; - } - - public function getScheme() - { - return $this->_scheme; - } - - public function getRootNode() - { - if (isset ($this->_rootNode) == false) - { - $result = $this->_session->repositoryService->get( - array( - "where" => array( - "store" => $this->__toArray()))); - - $this->_rootNode = Node::createFromWebServiceData($this->_session, $result->getReturn); - } - - return $this->_rootNode; - } -} +. + */ + +require_once 'BaseObject.php'; +require_once 'Node.php'; + +class Store extends BaseObject +{ + protected $_session; + protected $_address; + protected $_scheme; + protected $_rootNode; + + public function __construct($session, $address, $scheme = "workspace") + { + $this->_session = $session; + $this->_address = $address; + $this->_scheme = $scheme; + } + + public function __toString() + { + return $this->scheme . "://" . $this->address; + } + + public function __toArray() + { + return array( + "scheme" => $this->_scheme, + "address" => $this->_address); + } + + public function getAddress() + { + return $this->_address; + } + + public function getScheme() + { + return $this->_scheme; + } + + public function getRootNode() + { + if (isset ($this->_rootNode) == false) + { + $result = $this->_session->repositoryService->get( + array( + "where" => array( + "store" => $this->__toArray()))); + + $this->_rootNode = Node::createFromWebServiceData($this->_session, $result->getReturn); + } + + return $this->_rootNode; + } +} ?> \ No newline at end of file diff --git a/lib/alfresco/Service/Version.php b/lib/alfresco/Service/Version.php index 6087b665595..74f7213700d 100644 --- a/lib/alfresco/Service/Version.php +++ b/lib/alfresco/Service/Version.php @@ -1,200 +1,194 @@ -_session = $session; - $this->_store = $store; - $this->_id = $id; - $this->_description = $description; - $this->_major = $major; - $this->_properties = null; - $this->_aspects = null; - $this->_type = null; - } - - /** - * __get override. - * - * If called with a valid property short name, the frozen value of that property is returned. - * - * @return String the appropriate property value, null if none found - */ - public function __get($name) - { - $fullName = $this->_session->namespaceMap->getFullName($name); - if ($fullName != $name) - { - $this->populateProperties(); - if (array_key_exists($fullName, $this->_properties) == true) - { - return $this->_properties[$fullName]; - } - else - { - return null; - } - } - else - { - return parent::__get($name); - } - } - - /** - * Gets session - * - * @return Session the session - */ - public function getSession() - { - return $this->_session; - } - - /** - * Get the frozen nodes store - * - * @return Store the store - */ - public function getStore() - { - return $this->_store; - } - - public function getId() - { - return $this->_id; - } - - public function getDescription() - { - return $this->_description; - } - - public function getMajor() - { - return $this->_major; - } - - public function getType() - { - return $this->_type; - } - - public function getProperties() - { - return $this->_properties; - } - - public function getAspects() - { - return $this->_aspects; - } - - private function populateProperties() - { - if ($this->_properties == null) - { - $result = $this->_session->repositoryService->get(array ( - "where" => array ( - "nodes" => array( - "store" => $this->_store->__toArray(), - "uuid" => $this->_id)))); - - $this->populateFromWebServiceNode($result->getReturn); - } - } - - private function populateFromWebServiceNode($webServiceNode) - { - $this->_type = $webServiceNode->type; - - // Get the aspects - $this->_aspects = array(); - $aspects = $webServiceNode->aspects; - if (is_array($aspects) == true) - { - foreach ($aspects as $aspect) - { - $this->_aspects[] = $aspect; - } - } - else - { - $this->_aspects[] = $aspects; - } - - // Set the property values - $this->_properties = array(); - foreach ($webServiceNode->properties as $propertyDetails) - { - $name = $propertyDetails->name; - $isMultiValue = $propertyDetails->isMultiValue; - $value = null; - if ($isMultiValue == false) - { - $value = $propertyDetails->value; - if ($this->isContentData($value) == true) - { - $value = new ContentData($this, $name); - } - } - else - { - $value = $propertyDetails->values; - } - - $this->_properties[$name] = $value; - } - } - } -?> +. + */ + + + /** + * Version class + * + * @author Roy Wetherall + */ + class Version extends BaseObject + { + private $_session; + private $_store; + private $_id; + private $_description; + private $_major; + private $_properties; + private $_type; + private $_aspects; + + /** + * Constructor + * + * @param $session the session that the version is tied to + * @param @store the store that the forzen node is stored in + * @prarm @id the id of the frozen node + * @param @description the description of the version + * @param @major indicates whether this is a major or minor revision + */ + public function __construct($session, $store, $id, $description=null, $major=false) + { + $this->_session = $session; + $this->_store = $store; + $this->_id = $id; + $this->_description = $description; + $this->_major = $major; + $this->_properties = null; + $this->_aspects = null; + $this->_type = null; + } + + /** + * __get override. + * + * If called with a valid property short name, the frozen value of that property is returned. + * + * @return String the appropriate property value, null if none found + */ + public function __get($name) + { + $fullName = $this->_session->namespaceMap->getFullName($name); + if ($fullName != $name) + { + $this->populateProperties(); + if (array_key_exists($fullName, $this->_properties) == true) + { + return $this->_properties[$fullName]; + } + else + { + return null; + } + } + else + { + return parent::__get($name); + } + } + + /** + * Gets session + * + * @return Session the session + */ + public function getSession() + { + return $this->_session; + } + + /** + * Get the frozen nodes store + * + * @return Store the store + */ + public function getStore() + { + return $this->_store; + } + + public function getId() + { + return $this->_id; + } + + public function getDescription() + { + return $this->_description; + } + + public function getMajor() + { + return $this->_major; + } + + public function getType() + { + return $this->_type; + } + + public function getProperties() + { + return $this->_properties; + } + + public function getAspects() + { + return $this->_aspects; + } + + private function populateProperties() + { + if ($this->_properties == null) + { + $result = $this->_session->repositoryService->get(array ( + "where" => array ( + "nodes" => array( + "store" => $this->_store->__toArray(), + "uuid" => $this->_id)))); + + $this->populateFromWebServiceNode($result->getReturn); + } + } + + private function populateFromWebServiceNode($webServiceNode) + { + $this->_type = $webServiceNode->type; + + // Get the aspects + $this->_aspects = array(); + $aspects = $webServiceNode->aspects; + if (is_array($aspects) == true) + { + foreach ($aspects as $aspect) + { + $this->_aspects[] = $aspect; + } + } + else + { + $this->_aspects[] = $aspects; + } + + // Set the property values + $this->_properties = array(); + foreach ($webServiceNode->properties as $propertyDetails) + { + $name = $propertyDetails->name; + $isMultiValue = $propertyDetails->isMultiValue; + $value = null; + if ($isMultiValue == false) + { + $value = $propertyDetails->value; + if ($this->isContentData($value) == true) + { + $value = new ContentData($this, $name); + } + } + else + { + $value = $propertyDetails->values; + } + + $this->_properties[$name] = $value; + } + } + } +?> diff --git a/lib/alfresco/Service/VersionHistory.php b/lib/alfresco/Service/VersionHistory.php index 57c2ea7f8e7..baabab4044b 100644 --- a/lib/alfresco/Service/VersionHistory.php +++ b/lib/alfresco/Service/VersionHistory.php @@ -1,80 +1,74 @@ -_node = $node; - $this->populateVersionHistory(); - } - - /** - * Get the node that this version history relates to - */ - public function getNode() - { - return $this->_node; - } - - /** - * Get a list of the versions in the version history - */ - public function getVersions() - { - return $this->_versions; - } - - /** - * Populate the version history - */ - private function populateVersionHistory() - { - // Use the web service API to get the version history for this node - $client = WebServiceFactory::getAuthoringService($this->_node->session->repository->connectionUrl, $this->_node->session->ticket); - $result = $client->getVersionHistory(array("node" => $this->_node->__toArray())); - //var_dump($result); - - // TODO populate the version history from the result of the web service call - } - } -?> +. + */ + + /** + * Version history class. + * + * @author Roy Wetherall + */ + class VersionHistory extends BaseObject + { + /** Node to which this version history relates */ + private $_node; + + /** Array of versions */ + private $_versions; + + /** + * Constructor + * + * @param $node the node that this version history apples to + */ + public function __construct($node) + { + $this->_node = $node; + $this->populateVersionHistory(); + } + + /** + * Get the node that this version history relates to + */ + public function getNode() + { + return $this->_node; + } + + /** + * Get a list of the versions in the version history + */ + public function getVersions() + { + return $this->_versions; + } + + /** + * Populate the version history + */ + private function populateVersionHistory() + { + // Use the web service API to get the version history for this node + $client = WebServiceFactory::getAuthoringService($this->_node->session->repository->connectionUrl, $this->_node->session->ticket); + $result = $client->getVersionHistory(array("node" => $this->_node->__toArray())); + //var_dump($result); + + // TODO populate the version history from the result of the web service call + } + } +?> diff --git a/lib/alfresco/Service/WebService/AlfrescoWebService.php b/lib/alfresco/Service/WebService/AlfrescoWebService.php index 8f2edf5d2e6..a91d170bd11 100644 --- a/lib/alfresco/Service/WebService/AlfrescoWebService.php +++ b/lib/alfresco/Service/WebService/AlfrescoWebService.php @@ -1,118 +1,111 @@ - true, 'exceptions' => true), $ticket = null) - { - // Store the current ticket - $this->ticket = $ticket; - - // Call the base class - parent::__construct($wsdl, $options); - } - - public function __call($function_name, $arguments=array()) - { - return $this->__soapCall($function_name, $arguments); - } - - public function __soapCall($function_name, $arguments=array(), $options=array(), $input_headers=array(), $output_headers=array()) - { - if (isset($this->ticket)) - { - // Automatically add a security header - $input_headers[] = new SoapHeader($this->securityExtNS, "Security", null, 1); - - // Set the JSESSION cookie value - // change by moodle - $sessionId = Alfresco_Repository::getSessionId($this->ticket); - if ($sessionId != null) - { - $this->__setCookie("JSESSIONID", $sessionId); - } - } - - return parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers); - } - - public function __doRequest($request, $location, $action, $version) - { - // If this request requires authentication we have to manually construct the - // security headers. - if (isset($this->ticket)) - { - $dom = new DOMDocument("1.0"); - $dom->loadXML($request); - - $securityHeader = $dom->getElementsByTagName("Security"); - - if ($securityHeader->length != 1) - { - throw new Exception("Expected length: 1, Received: " . $securityHeader->length . ". No Security Header, or more than one element called Security!"); - } - - $securityHeader = $securityHeader->item(0); - - // Construct Timestamp Header - $timeStamp = $dom->createElementNS($this->wsUtilityNS, "Timestamp"); - $createdDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+24, date("i"), date("s"), date("m"), date("d"), date("Y"))); - $expiresDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+25, date("i"), date("s"), date("m"), date("d"), date("Y"))); - $created = new DOMElement("Created", $createdDate, $this->wsUtilityNS); - $expires = new DOMElement("Expires", $expiresDate, $this->wsUtilityNS); - $timeStamp->appendChild($created); - $timeStamp->appendChild($expires); - - // Construct UsernameToken Header - $userNameToken = $dom->createElementNS($this->securityExtNS, "UsernameToken"); - $userName = new DOMElement("Username", "username", $this->securityExtNS); - $passWord = $dom->createElementNS($this->securityExtNS, "Password"); - $typeAttr = new DOMAttr("Type", $this->passwordType); - $passWord->appendChild($typeAttr); - $passWord->appendChild($dom->createTextNode($this->ticket)); - $userNameToken->appendChild($userName); - $userNameToken->appendChild($passWord); - - // Construct Security Header - $securityHeader->appendChild($timeStamp); - $securityHeader->appendChild($userNameToken); - - // Save the XML Request - $request = $dom->saveXML(); - } - - return parent::__doRequest($request, $location, $action, $version); - } -} - -?> +. + */ + +class AlfrescoWebService extends SoapClient +{ + private $securityExtNS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; + private $wsUtilityNS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"; + private $passwordType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"; + + private $ticket; + + public function __construct($wsdl, $options = array('trace' => true, 'exceptions' => true), $ticket = null) + { + // Store the current ticket + $this->ticket = $ticket; + + // Call the base class + parent::__construct($wsdl, $options); + } + + public function __call($function_name, $arguments=array()) + { + return $this->__soapCall($function_name, $arguments); + } + + public function __soapCall($function_name, $arguments=array(), $options=array(), $input_headers=array(), $output_headers=array()) + { + if (isset($this->ticket)) + { + // Automatically add a security header + $input_headers[] = new SoapHeader($this->securityExtNS, "Security", null, 1); + + // Set the JSESSION cookie value + $sessionId = Repository::getSessionId($this->ticket); + if ($sessionId != null) + { + $this->__setCookie("JSESSIONID", $sessionId); + } + } + + return parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers); + } + + public function __doRequest($request, $location, $action, $version) + { + // If this request requires authentication we have to manually construct the + // security headers. + if (isset($this->ticket)) + { + $dom = new DOMDocument("1.0"); + $dom->loadXML($request); + + $securityHeader = $dom->getElementsByTagName("Security"); + + if ($securityHeader->length != 1) + { + throw new Exception("Expected length: 1, Received: " . $securityHeader->length . ". No Security Header, or more than one element called Security!"); + } + + $securityHeader = $securityHeader->item(0); + + // Construct Timestamp Header + $timeStamp = $dom->createElementNS($this->wsUtilityNS, "Timestamp"); + $createdDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+24, date("i"), date("s"), date("m"), date("d"), date("Y"))); + $expiresDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+25, date("i"), date("s"), date("m"), date("d"), date("Y"))); + $created = new DOMElement("Created", $createdDate, $this->wsUtilityNS); + $expires = new DOMElement("Expires", $expiresDate, $this->wsUtilityNS); + $timeStamp->appendChild($created); + $timeStamp->appendChild($expires); + + // Construct UsernameToken Header + $userNameToken = $dom->createElementNS($this->securityExtNS, "UsernameToken"); + $userName = new DOMElement("Username", "username", $this->securityExtNS); + $passWord = $dom->createElementNS($this->securityExtNS, "Password"); + $typeAttr = new DOMAttr("Type", $this->passwordType); + $passWord->appendChild($typeAttr); + $passWord->appendChild($dom->createTextNode($this->ticket)); + $userNameToken->appendChild($userName); + $userNameToken->appendChild($passWord); + + // Construct Security Header + $securityHeader->appendChild($timeStamp); + $securityHeader->appendChild($userNameToken); + + // Save the XML Request + $request = $dom->saveXML(); + } + + return parent::__doRequest($request, $location, $action, $version); + } +} + +?> diff --git a/lib/alfresco/Service/WebService/WebServiceFactory.php b/lib/alfresco/Service/WebService/WebServiceFactory.php index b312b6a1cc6..4c5fd575410 100644 --- a/lib/alfresco/Service/WebService/WebServiceFactory.php +++ b/lib/alfresco/Service/WebService/WebServiceFactory.php @@ -1,64 +1,57 @@ -libdir.'/alfresco/Service/WebService/AlfrescoWebService.php'); - -class WebServiceFactory -{ - public static function getAuthenticationService($path) - { - $path .= '/AuthenticationService?wsdl'; - return new AlfrescoWebService($path, array('location'=>$path)); - } - - public static function getRepositoryService($path, $ticket) - { - $path .= '/RepositoryService?wsdl'; - return new AlfrescoWebService($path, array('location'=>$path), $ticket); - } - - public static function getContentService($path, $ticket) - { - $path .= '/ContentService?wsdl'; - return new AlfrescoWebService($path, array('location'=>$path), $ticket); - } - - public static function getAdministrationService($path, $ticket) - { - $path .= '/AdministrationService?wsdl'; - return new AlfrescoWebService($path, array('location'=>$path), $ticket); - } - - public static function getAuthoringService($path, $ticket) - { - $path .= '/AuthoringService?wsdl'; - return new AlfrescoWebService($path, array('location'=>$path), $ticket); - } -} - -?> +. + */ + +require_once 'AlfrescoWebService.php'; + +class WebServiceFactory +{ + public static function getAuthenticationService($path) + { + $path .= '/AuthenticationService?wsdl'; + return new AlfrescoWebService($path, array()); + } + + public static function getRepositoryService($path, $ticket) + { + $path .= '/RepositoryService?wsdl'; + return new AlfrescoWebService($path, array(), $ticket); + } + + public static function getContentService($path, $ticket) + { + $path .= '/ContentService?wsdl'; + return new AlfrescoWebService($path, array(), $ticket); + } + + public static function getAdministrationService($path, $ticket) + { + $path .= '/AdministrationService?wsdl'; + return new AlfrescoWebService($path, array(), $ticket); + } + + public static function getAuthoringService($path, $ticket) + { + $path .= '/AuthoringService?wsdl'; + return new AlfrescoWebService($path, array(), $ticket); + } +} + +?> \ No newline at end of file From ce9e6877015710e9ad4555402039ba28d17845b8 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 19 Jul 2012 13:29:42 +0800 Subject: [PATCH 016/106] MDL-34400 Alfresco: Altering the API for integration into Moodle --- lib/alfresco/README_MOODLE.txt | 49 +++++++++++++++---- lib/alfresco/Service/ContentData.php | 2 +- lib/alfresco/Service/Functions.php | 4 +- lib/alfresco/Service/Logger/Logger.php | 2 +- lib/alfresco/Service/Node.php | 14 +++--- lib/alfresco/Service/Repository.php | 12 +++-- lib/alfresco/Service/Session.php | 8 +-- lib/alfresco/Service/SpacesStore.php | 4 +- lib/alfresco/Service/Store.php | 4 +- .../Service/WebService/AlfrescoWebService.php | 6 +-- .../Service/WebService/WebServiceFactory.php | 2 +- 11 files changed, 70 insertions(+), 37 deletions(-) diff --git a/lib/alfresco/README_MOODLE.txt b/lib/alfresco/README_MOODLE.txt index 308e3c3b0de..83179f07fdb 100644 --- a/lib/alfresco/README_MOODLE.txt +++ b/lib/alfresco/README_MOODLE.txt @@ -1,17 +1,46 @@ - == CHANGELOG == -1. Rename class name , see Service/Repository.php & Service/WebService/AlfrescoWebService.php -2. Change library path name -3. In Alfresco_Repository class construct function, set _port to 80 if it is not specified -4. MDL-20876 - replaced deprecated split() with explode() -== Alfresco PHP Libarary == +1. Rename class name 'Repository' to 'Alfresco_Repository' in + - Service/Repository.php + - Service/Webservice/AlfrescoWebService.php + +2. Update path for require_once() in + - Service/Logger/Logger.php + - Service/WebService/WebServiceFactory.php + - Service/ContentData.php + - Service/Functions.php + - Service/Node.php + - Service/Repository.php + - Service/Session.php + - Service/SpacesStore.php + - Service/Store.php + +3. In Alfresco_Repository::__construct(), set _port to 80 when not specified + + @@ -46,7 +46,11 @@ class Alfresco_Repository extends BaseObject + $this->_connectionUrl = $connectionUrl; + $parts = parse_url($connectionUrl); + $this->_host = $parts["host"]; + - $this->_port = $parts["port"]; + + if (empty($parts["port"])) { + + $this->_port = 80; + + } else { + + $this->_port = $parts["port"]; + + } + +4. Reapply changes from MDL-20876 Fix depreacted split() calls (bed733c) + +5. Fix strict standards in Service/WebService/AlfrescoWebService.php + - AlfrescoWebService::__soapCall() arguments do not match SoapClient::__soapCall() + - AlfrescoWebService::__doRequest() arguments do not match SoapClient::__soapCall() + +== Alfresco PHP Library == Installation and developer documentation for the Alfresco PHP Library can be found on the Alfresco Wiki. -Get the source from http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root/modules/php-sdk +Get the source from http://code.google.com/p/alfresco-php-sdk/ == Documentation Links == -Installation Instructions - http://wiki.alfresco.com/wiki/Alfresco_PHP_Library_Installation_Instructions -MediaWiki Integration Installation Instructions - http://wiki.alfresco.com/wiki/Alfresco_MediaWiki_Installation_Instructions -PHP API Documentation - http://wiki.alfresco.com/wiki/Alfresco_PHP_API +Installation Instructions - http://code.google.com/p/alfresco-php-sdk/wiki/AlfrescoPHPLibraryInstallationInstructions +MediaWiki Integration Installation Instructions - http://code.google.com/p/alfresco-php-sdk/wiki/AlfrescoMediaWikiInstallationInstructions +PHP API Documentation - http://code.google.com/p/alfresco-php-sdk/wiki/AlfrescoPHPAPI \ No newline at end of file diff --git a/lib/alfresco/Service/ContentData.php b/lib/alfresco/Service/ContentData.php index 6c392a26ffd..a2a34d90ded 100644 --- a/lib/alfresco/Service/ContentData.php +++ b/lib/alfresco/Service/ContentData.php @@ -18,7 +18,7 @@ * along with Alfresco. If not, see . */ -require_once("Alfresco/Service/Functions.php"); +require_once($CFG->libdir."/alfresco/Service/Functions.php"); class ContentData extends BaseObject { diff --git a/lib/alfresco/Service/Functions.php b/lib/alfresco/Service/Functions.php index a0918e38ff8..d94e2412139 100644 --- a/lib/alfresco/Service/Functions.php +++ b/lib/alfresco/Service/Functions.php @@ -18,8 +18,8 @@ * along with Alfresco. If not, see . */ - require_once("Alfresco/Service/Repository.php"); - require_once("Alfresco/Service/Session.php"); + require_once($CFG->libdir."/alfresco/Service/Repository.php"); + require_once($CFG->libdir."/alfresco/Service/Session.php"); /** * Uploads a file into content store and returns the content data string which diff --git a/lib/alfresco/Service/Logger/Logger.php b/lib/alfresco/Service/Logger/Logger.php index 54e77d27be8..6916cb926bc 100644 --- a/lib/alfresco/Service/Logger/Logger.php +++ b/lib/alfresco/Service/Logger/Logger.php @@ -18,7 +18,7 @@ * along with Alfresco. If not, see . */ - require_once "LoggerConfig.php"; + require_once $CFG->libdir."/alfresco/Service/Logger/LoggerConfig.php"; class Logger { diff --git a/lib/alfresco/Service/Node.php b/lib/alfresco/Service/Node.php index a389dc07b9e..71bc3623ff0 100644 --- a/lib/alfresco/Service/Node.php +++ b/lib/alfresco/Service/Node.php @@ -18,13 +18,13 @@ * along with Alfresco. If not, see . */ -require_once 'Store.php'; -require_once 'ChildAssociation.php'; -require_once 'Association.php'; -require_once 'NamespaceMap.php'; -require_once 'ContentData.php'; -require_once 'VersionHistory.php'; -require_once 'Version.php'; +require_once $CFG->libdir.'/alfresco/Service/Store.php'; +require_once $CFG->libdir.'/alfresco/Service/ChildAssociation.php'; +require_once $CFG->libdir.'/alfresco/Service/Association.php'; +require_once $CFG->libdir.'/alfresco/Service/NamespaceMap.php'; +require_once $CFG->libdir.'/alfresco/Service/ContentData.php'; +require_once $CFG->libdir.'/alfresco/Service/VersionHistory.php'; +require_once $CFG->libdir.'/alfresco/Service/Version.php'; class Node extends BaseObject { diff --git a/lib/alfresco/Service/Repository.php b/lib/alfresco/Service/Repository.php index 9ac38f6c42b..79f9c10fa88 100644 --- a/lib/alfresco/Service/Repository.php +++ b/lib/alfresco/Service/Repository.php @@ -18,8 +18,8 @@ * along with Alfresco. If not, see . */ -require_once 'Alfresco/Service/WebService/WebServiceFactory.php'; -require_once 'Alfresco/Service/BaseObject.php'; +require_once $CFG->libdir.'/alfresco/Service/WebService/WebServiceFactory.php'; +require_once $CFG->libdir.'/alfresco/Service/BaseObject.php'; if (isset($_SESSION) == false) { @@ -27,7 +27,7 @@ if (isset($_SESSION) == false) session_start(); } -class Repository extends BaseObject +class Alfresco_Repository extends BaseObject { private $_connectionUrl; private $_host; @@ -38,7 +38,11 @@ class Repository extends BaseObject $this->_connectionUrl = $connectionUrl; $parts = parse_url($connectionUrl); $this->_host = $parts["host"]; - $this->_port = $parts["port"]; + if (empty($parts["port"])) { + $this->_port = 80; + } else { + $this->_port = $parts["port"]; + } } public function getConnectionUrl() diff --git a/lib/alfresco/Service/Session.php b/lib/alfresco/Service/Session.php index 85d5ac81226..9204d7da574 100644 --- a/lib/alfresco/Service/Session.php +++ b/lib/alfresco/Service/Session.php @@ -18,9 +18,9 @@ * along with Alfresco. If not, see . */ -require_once 'Store.php'; -require_once 'Node.php'; -require_once 'WebService/WebServiceFactory.php'; +require_once $CFG->libdir.'/alfresco/Service/Store.php'; +require_once $CFG->libdir.'/alfresco/Service/Node.php'; +require_once $CFG->libdir.'/alfresco/Service/WebService/WebServiceFactory.php'; class Session extends BaseObject { @@ -98,7 +98,7 @@ class Session extends BaseObject */ public function getStoreFromString($value) { - list($scheme, $address) = split("://", $value); + list($scheme, $address) = explode("://", $value); return new Store($this, $address, $scheme); } diff --git a/lib/alfresco/Service/SpacesStore.php b/lib/alfresco/Service/SpacesStore.php index 92fc90b23d1..b595432e935 100644 --- a/lib/alfresco/Service/SpacesStore.php +++ b/lib/alfresco/Service/SpacesStore.php @@ -18,8 +18,8 @@ * along with Alfresco. If not, see . */ -require_once 'Store.php'; -require_once 'Node.php'; +require_once $CFG->libdir.'/alfresco/Service/Store.php'; +require_once $CFG->libdir.'/alfresco/Service/Node.php'; class SpacesStore extends Store { diff --git a/lib/alfresco/Service/Store.php b/lib/alfresco/Service/Store.php index 3f2f8647daf..dca6545f912 100644 --- a/lib/alfresco/Service/Store.php +++ b/lib/alfresco/Service/Store.php @@ -18,8 +18,8 @@ * along with Alfresco. If not, see . */ -require_once 'BaseObject.php'; -require_once 'Node.php'; +require_once $CFG->libdir.'/alfresco/Service/BaseObject.php'; +require_once $CFG->libdir.'/alfresco/Service/Node.php'; class Store extends BaseObject { diff --git a/lib/alfresco/Service/WebService/AlfrescoWebService.php b/lib/alfresco/Service/WebService/AlfrescoWebService.php index a91d170bd11..b549755b467 100644 --- a/lib/alfresco/Service/WebService/AlfrescoWebService.php +++ b/lib/alfresco/Service/WebService/AlfrescoWebService.php @@ -41,7 +41,7 @@ class AlfrescoWebService extends SoapClient return $this->__soapCall($function_name, $arguments); } - public function __soapCall($function_name, $arguments=array(), $options=array(), $input_headers=array(), $output_headers=array()) + public function __soapCall($function_name, $arguments=array(), $options=array(), $input_headers=array(), &$output_headers=array()) { if (isset($this->ticket)) { @@ -49,7 +49,7 @@ class AlfrescoWebService extends SoapClient $input_headers[] = new SoapHeader($this->securityExtNS, "Security", null, 1); // Set the JSESSION cookie value - $sessionId = Repository::getSessionId($this->ticket); + $sessionId = Alfresco_Repository::getSessionId($this->ticket); if ($sessionId != null) { $this->__setCookie("JSESSIONID", $sessionId); @@ -59,7 +59,7 @@ class AlfrescoWebService extends SoapClient return parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers); } - public function __doRequest($request, $location, $action, $version) + public function __doRequest($request, $location, $action, $version, $one_way = 0) { // If this request requires authentication we have to manually construct the // security headers. diff --git a/lib/alfresco/Service/WebService/WebServiceFactory.php b/lib/alfresco/Service/WebService/WebServiceFactory.php index 4c5fd575410..b9683719591 100644 --- a/lib/alfresco/Service/WebService/WebServiceFactory.php +++ b/lib/alfresco/Service/WebService/WebServiceFactory.php @@ -19,7 +19,7 @@ * along with Alfresco. If not, see . */ -require_once 'AlfrescoWebService.php'; +require_once $CFG->libdir.'/alfresco/Service/WebService/AlfrescoWebService.php'; class WebServiceFactory { From a2584294b32d50daed4715c103c2ce76ca886671 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 19 Jul 2012 13:39:06 +0800 Subject: [PATCH 017/106] MDL-29271 Alfresco: Repository can browse sites --- repository/alfresco/lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repository/alfresco/lib.php b/repository/alfresco/lib.php index b5a871f3124..9a34b9d5b53 100644 --- a/repository/alfresco/lib.php +++ b/repository/alfresco/lib.php @@ -165,9 +165,9 @@ class repository_alfresco extends repository { $file_filter = "{http://www.alfresco.org/model/content/1.0}content"; // top level sites folder - $sites_filter = "{http://www.alfresco.org/model/content/1.0}sites"; + $sites_filter = "{http://www.alfresco.org/model/site/1.0}sites"; // individual site - $site_filter = "{http://www.alfresco.org/model/content/1.0}site"; + $site_filter = "{http://www.alfresco.org/model/site/1.0}site"; foreach ($this->current_node->children as $child) { From 21a4e24cab5977cf69f1fea3b84c5b8d3d660d05 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Fri, 13 Jul 2012 14:28:23 +1200 Subject: [PATCH 018/106] MDL-34285 condition: Added is not empty option for user profile conditions and moved strings. As part of this change I added a new condition for user fields: is not equal. I also copied the strings being used from the filters lang file to the condition lang file and changed the uses in code. AMOS BEGIN CPY [contains,filters],[contains,condition] CPY [doesnotcontain,filters],[doesnotcontain,condition] CPY [isequalto,filters],[isequalto,condition] CPY [startswith,filters],[startswith,condition] CPY [endswith,filters],[endswith,condition] CPY [isempty,filters],[isempty,condition] AMOS END --- lang/en/condition.php | 15 ++++++++++++++- lib/conditionlib.php | 29 +++++++++++++++++++---------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lang/en/condition.php b/lang/en/condition.php index 5851e6e1f61..a888d8c7747 100644 --- a/lang/en/condition.php +++ b/lang/en/condition.php @@ -47,7 +47,10 @@ $string['completion_fail'] = 'must be complete with fail grade'; $string['completion_incomplete'] = 'must not be marked complete'; $string['completion_pass'] = 'must be complete with pass grade'; $string['configenableavailability'] = 'When enabled, this lets you set conditions (based on date, grade, or completion) that control whether an activity or resource can be accessed.'; +$string['contains'] = 'contains'; +$string['doesnotcontain'] = 'doesn\'t contain'; $string['enableavailability'] = 'Enable conditional access'; +$string['endswith'] = 'ends with'; $string['fielddeclaredmultipletimes'] = 'You can not declare the same field more than once per activity.'; $string['grade_atleast'] = 'must be at least'; $string['gradecondition'] = 'Grade condition'; @@ -62,6 +65,9 @@ $string['grade_upto'] = 'and less than'; $string['gradeitembutnolimits'] = 'You must enter an upper or lower limit, or both.'; $string['gradelimitsbutnoitem'] = 'You must choose a grade item.'; $string['gradesmustbenumeric'] = 'The minimum and maximum grades must be numeric (or blank).'; +$string['isempty'] = 'is empty'; +$string['isequalto'] = 'is equal to'; +$string['isnotempty'] = 'is not empty'; $string['none'] = '(none)'; $string['notavailableyet'] = 'Not available yet'; $string['requires_completion_0'] = 'Not available unless the activity {$a} is incomplete.'; @@ -76,13 +82,20 @@ $string['requires_grade_any'] = 'Not available until you have a grade in libdir.'/completionlib.php'); @@ -583,12 +587,13 @@ abstract class condition_info_base { */ public static function get_condition_user_field_operators() { return array( - OP_CONTAINS => get_string('contains', 'filters'), - OP_DOES_NOT_CONTAIN => get_string('doesnotcontain', 'filters'), - OP_IS_EQUAL_TO => get_string('isequalto', 'filters'), - OP_STARTS_WITH => get_string('startswith', 'filters'), - OP_ENDS_WITH => get_string('endswith', 'filters'), - OP_IS_EMPTY => get_string('isempty', 'filters') + OP_CONTAINS => get_string('contains', 'condition'), + OP_DOES_NOT_CONTAIN => get_string('doesnotcontain', 'condition'), + OP_IS_EQUAL_TO => get_string('isequalto', 'condition'), + OP_STARTS_WITH => get_string('startswith', 'condition'), + OP_ENDS_WITH => get_string('endswith', 'condition'), + OP_IS_EMPTY => get_string('isempty', 'condition'), + OP_IS_NOT_EMPTY => get_string('isnotempty', 'condition'), ); } @@ -801,9 +806,9 @@ abstract class condition_info_base { foreach ($this->item->conditionsfield as $field => $details) { $a = new stdclass; $a->field = $details->fieldname; - $a->operator = get_string($details->operator, 'filters'); + $a->operator = get_string($details->operator, 'condition'); $a->value = $details->value; - $information .= get_string('requires_user_field_restriction', 'condition', $a) . ' '; + $information .= get_string('requires_user_field', 'condition', $a) . ' '; } } @@ -1008,9 +1013,8 @@ abstract class condition_info_base { $available = false; $a = new stdClass(); $a->field = $details->fieldname; - $a->operator = get_string($details->operator, 'filters'); $a->value = $details->value; - $information .= get_string('requires_user_field_restriction', 'condition', $a) . ' '; + $information .= get_string('requires_user_field_'.$details->operator, 'condition', $a) . ' '; } } } @@ -1224,6 +1228,11 @@ abstract class condition_info_base { $fieldconditionmet = false; } break; + case OP_IS_NOT_EMPTY: // is not empty + if (empty($uservalue)) { + $fieldconditionmet = false; + } + break; } return $fieldconditionmet; } From 1c8d09338e7d1d9295fdeb1d42b59db79b449df4 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Thu, 19 Jul 2012 19:29:47 +1200 Subject: [PATCH 019/106] MDL-34285 condition: Fixed up missing operator --- lib/conditionlib.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/conditionlib.php b/lib/conditionlib.php index a76a4f46dcb..f2fe8c7c41f 100644 --- a/lib/conditionlib.php +++ b/lib/conditionlib.php @@ -806,9 +806,8 @@ abstract class condition_info_base { foreach ($this->item->conditionsfield as $field => $details) { $a = new stdclass; $a->field = $details->fieldname; - $a->operator = get_string($details->operator, 'condition'); $a->value = $details->value; - $information .= get_string('requires_user_field', 'condition', $a) . ' '; + $information .= get_string('requires_user_field_'.$details->operator, 'condition', $a) . ' '; } } From 83ea0cc17e54500ea0feeaf9f85f6126f03bed5e Mon Sep 17 00:00:00 2001 From: Adam Olley Date: Wed, 27 Jun 2012 16:48:46 +0800 Subject: [PATCH 020/106] MDL-19430 My Moodle: Merged Netspot My Course Overview Block for Moodle 2 --- blocks/course_overview/README | 33 +++ .../course_overview/block_course_overview.php | 112 ++++---- blocks/course_overview/db/install.php | 28 ++ blocks/course_overview/db/upgrade.php | 30 +++ .../lang/en/block_course_overview.php | 26 ++ blocks/course_overview/locallib.php | 167 ++++++++++++ blocks/course_overview/module.js | 226 +++++++++++++++++ blocks/course_overview/move.php | 58 +++++ blocks/course_overview/pix/collapse_all.png | Bin 0 -> 3077 bytes .../pix/colltopics-arrow-current.png | Bin 0 -> 3168 bytes .../pix/colltopics-arrow-down-current.png | Bin 0 -> 3157 bytes .../pix/colltopics-arrow-down.png | Bin 0 -> 3280 bytes .../pix/colltopics-arrow-right.png | Bin 0 -> 3300 bytes blocks/course_overview/pix/expand_all.png | Bin 0 -> 3066 bytes blocks/course_overview/renderer.php | 240 ++++++++++++++++++ blocks/course_overview/save.php | 31 +++ blocks/course_overview/settings.php | 16 ++ blocks/course_overview/styles.css | 83 ++++++ blocks/course_overview/version.php | 4 +- 19 files changed, 984 insertions(+), 70 deletions(-) create mode 100644 blocks/course_overview/README create mode 100644 blocks/course_overview/db/install.php create mode 100644 blocks/course_overview/db/upgrade.php create mode 100644 blocks/course_overview/locallib.php create mode 100644 blocks/course_overview/module.js create mode 100644 blocks/course_overview/move.php create mode 100644 blocks/course_overview/pix/collapse_all.png create mode 100644 blocks/course_overview/pix/colltopics-arrow-current.png create mode 100644 blocks/course_overview/pix/colltopics-arrow-down-current.png create mode 100644 blocks/course_overview/pix/colltopics-arrow-down.png create mode 100644 blocks/course_overview/pix/colltopics-arrow-right.png create mode 100644 blocks/course_overview/pix/expand_all.png create mode 100644 blocks/course_overview/renderer.php create mode 100644 blocks/course_overview/save.php create mode 100644 blocks/course_overview/settings.php create mode 100644 blocks/course_overview/styles.css diff --git a/blocks/course_overview/README b/blocks/course_overview/README new file mode 100644 index 00000000000..2aa3aa5e2ed --- /dev/null +++ b/blocks/course_overview/README @@ -0,0 +1,33 @@ +My Course Overview Block for Moodle 2 + +== Main feautres == + +Provides a user configurable list of the courses a user is enrolled in on their My Moodle page. + +The user can set the number of courses to have visible. + +Courses can be reordered in editing mode via drag and drop (with appropriate fallback when ajax disabled for the user). + +Each course can be expanded to show a list of activity icons alerting the user to updated modules or modules requiring attention. + +Optionally can display the shortnames of child courses under the heading of the course (site-wide option). + +Optionally can display a welcome area above the courses that welcomes the user and alerts them of any pending messages. + +== Installing and configuring == + +Place the code for the block under /blocks/my_course_overview and install the block via the Moodle upgrade process. + +== Credits == + +Coding: NetSpot (http://www.netspot.com.au) + +Jointly Funded and Designed by: + - Flinders University (http://www.flinders.edu.au) + - University of Canberra (http://www.canberra.edu.au) + +== See also == + +[https://github.com/netspotau/moodle-block_my_course_overview Github page] + +[[Category: Contributed code]] diff --git a/blocks/course_overview/block_course_overview.php b/blocks/course_overview/block_course_overview.php index df79e3bf2d4..78f45ca3575 100644 --- a/blocks/course_overview/block_course_overview.php +++ b/blocks/course_overview/block_course_overview.php @@ -1,5 +1,4 @@ dirroot.'/lib/weblib.php'); -require_once($CFG->dirroot . '/lib/formslib.php'); +require_once($CFG->dirroot.'/blocks/course_overview/locallib.php'); class block_course_overview extends block_base { /** * block initializations */ public function init() { - $this->title = get_string('pluginname', 'block_course_overview'); + $this->title = get_string('displaytitle', 'block_course_overview'); } /** @@ -41,82 +38,53 @@ class block_course_overview extends block_base { * @return object */ public function get_content() { - global $USER, $CFG; + global $USER, $CFG, $DB; + require_once($CFG->dirroot.'/user/profile/lib.php'); + if($this->content !== NULL) { return $this->content; } + $config = get_config('block_course_overview'); + $this->content = new stdClass(); $this->content->text = ''; $this->content->footer = ''; $content = array(); - // limits the number of courses showing up - $courses_limit = 21; - // FIXME: this should be a block setting, rather than a global setting - if (isset($CFG->mycoursesperpage)) { - $courses_limit = $CFG->mycoursesperpage; + $moving = optional_param('course_moveid', 0, PARAM_INT); + $updatemynumber = optional_param('mynumber', null, PARAM_INT); + if (!is_null($updatemynumber)) { + block_course_overview_update_mynumber($updatemynumber); } - $morecourses = false; - if ($courses_limit > 0) { - $courses_limit = $courses_limit + 1; + profile_load_custom_fields($USER); + list($courses_sorted, $courses_total) = block_course_overview_get_sorted_courses(); + $overviews = block_course_overview_get_overviews($courses_sorted); + + $renderer = $this->page->get_renderer('block_course_overview'); + if (!isset($config->showwelcomearea) || $config->showwelcomearea) { + $this->content->text = $renderer->welcome_area(); } - $courses = enrol_get_my_courses('id, shortname, modinfo', 'visible DESC,sortorder ASC', $courses_limit); - $site = get_site(); - $course = $site; //just in case we need the old global $course hack - - if (is_enabled_auth('mnet')) { - $remote_courses = get_my_remotecourses(); - } - if (empty($remote_courses)) { - $remote_courses = array(); + //number of sites to display + if ($this->page->user_is_editing()) { + $count = count(enrol_get_my_courses('id')); + $this->content->text .= $renderer->editing_bar_head($count); } - if (($courses_limit > 0) && (count($courses)+count($remote_courses) >= $courses_limit)) { - // get rid of any remote courses that are above the limit - $remote_courses = array_slice($remote_courses, 0, $courses_limit - count($courses), true); - if (count($courses) >= $courses_limit) { - //remove the 'marker' course that we retrieve just to see if we have more than $courses_limit - array_pop($courses); - } - $morecourses = true; - } - - - if (array_key_exists($site->id,$courses)) { - unset($courses[$site->id]); - } - - foreach ($courses as $c) { - if (isset($USER->lastcourseaccess[$c->id])) { - $courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id]; - } else { - $courses[$c->id]->lastaccess = 0; - } - } - - if (empty($courses) && empty($remote_courses)) { - $content[] = get_string('nocourses','my'); + if (empty($courses_sorted)) { + $this->content->text .= get_string('nocourses','my'); } else { - ob_start(); - - require_once $CFG->dirroot."/course/lib.php"; - print_overview($courses, $remote_courses); - - $content[] = ob_get_contents(); - ob_end_clean(); + //for each course, build category cache + $this->content->text .= $renderer->course_overview($courses_sorted, $overviews, $moving); + $this->content->text .= $renderer->hidden_courses($courses_total - count($courses_sorted)); + if ($this->page->user_is_editing() && ajaxenabled() && !$moving) { + $this->page->requires->js_init_call('M.block_course_overview.add_handles'); + } } - // if more than 20 courses - if ($morecourses) { - $content[] = '
...'; - } - - $this->content->text = implode($content); - return $this->content; } @@ -126,7 +94,7 @@ class block_course_overview extends block_base { * @return boolean */ public function has_config() { - return false; + return true; } /** @@ -135,7 +103,15 @@ class block_course_overview extends block_base { * @return array */ public function applicable_formats() { - return array('my-index'=>true); + return array('my-index' => true); + } + + public function instance_can_be_hidden() { + return false; + } + + public function hide_header() { + return true; } } ?> diff --git a/blocks/course_overview/db/install.php b/blocks/course_overview/db/install.php new file mode 100644 index 00000000000..67d6914cf8f --- /dev/null +++ b/blocks/course_overview/db/install.php @@ -0,0 +1,28 @@ +get_record('user_info_field', array('shortname' => 'mynumber'))) { + $field = new stdClass(); + $field->shortname = 'mynumber'; + $field->name = 'Number of courses on My Moodle'; + $field->datatype = 'text'; + $field->visible = 1; + $field->categoryid = 1; + + $DB->insert_record('user_info_field', $field); + } + + if (!$DB->get_record('user_info_field', array('shortname' => 'myorder'))) { + $field = new stdClass(); + $field->shortname = 'myorder'; + $field->name = 'Order of courses on My Moodle'; + $field->datatype = 'text'; + $field->visible = 0; + $field->categoryid = 1; + + $DB->insert_record('user_info_field', $field); + } +} \ No newline at end of file diff --git a/blocks/course_overview/db/upgrade.php b/blocks/course_overview/db/upgrade.php new file mode 100644 index 00000000000..f59f7a52468 --- /dev/null +++ b/blocks/course_overview/db/upgrade.php @@ -0,0 +1,30 @@ +get_record('user_info_field', array('shortname' => 'mynumber'))) { + $field = new stdClass(); + $field->shortname = 'mynumber'; + $field->name = 'Number of courses on My Moodle'; + $field->datatype = 'text'; + $field->visible = 1; + $field->categoryid = 1; + + $DB->insert_record('user_info_field', $field); + } + + if (!$DB->get_record('user_info_field', array('shortname' => 'myorder'))) { + $field = new stdClass(); + $field->shortname = 'myorder'; + $field->name = 'Order of courses on My Moodle'; + $field->datatype = 'text'; + $field->visible = 0; + $field->categoryid = 1; + + $DB->insert_record('user_info_field', $field); + } + upgrade_block_savepoint(true, 2012062800, 'course_overview'); + } + return true; +} diff --git a/blocks/course_overview/lang/en/block_course_overview.php b/blocks/course_overview/lang/en/block_course_overview.php index c103d8e2543..f7b2063b9aa 100644 --- a/blocks/course_overview/lang/en/block_course_overview.php +++ b/blocks/course_overview/lang/en/block_course_overview.php @@ -1,2 +1,28 @@ . + +function block_course_overview_get_overviews($courses) { + global $CFG, $USER, $DB, $OUTPUT; + $htmlarray = array(); + if ($modules = $DB->get_records('modules')) { + foreach ($modules as $mod) { + if (file_exists(dirname(__FILE__).'/../../mod/'.$mod->name.'/lib.php')) { + include_once(dirname(__FILE__).'/../../mod/'.$mod->name.'/lib.php'); + $fname = $mod->name.'_print_overview'; + if (function_exists($fname)) { + $fname($courses,$htmlarray); + } + } + } + } + return $htmlarray; +} + +function block_course_overview_update_mynumber($number) { + global $DB, $USER; + if ($field = $DB->get_record('user_info_field', array('shortname' => 'mynumber'))) { + if ($data = $DB->get_record('user_info_data', array('fieldid' => $field->id, 'userid' => $USER->id))) { + $data->data = $number; + $DB->update_record('user_info_data', $data); + } else { + $data = new stdClass(); + $data->fieldid = $field->id; + $data->userid = $USER->id; + $data->data = $number; + $DB->insert_record('user_info_data', $data); + } + } +} + +function block_course_overview_update_myorder($sortorder) { + global $DB, $USER; + if ($field = $DB->get_record('user_info_field', array('shortname' => 'myorder'))) { + if ($data = $DB->get_record('user_info_data', array('fieldid' => $field->id, 'userid' => $USER->id))) { + + $oldlist = explode(',', $data->data); + $newlist = explode(',', $sortorder); + foreach ($oldlist as $oldentry) { + if (!in_array($oldentry, $newlist)) { + $newlist[] = $oldentry; + } + } + $sortorder = implode(',', $newlist); + + $data->data = $sortorder; + $DB->update_record('user_info_data', $data); + } else { + $data = new stdClass(); + $data->fieldid = $field->id; + $data->userid = $USER->id; + $data->data = $sortorder; + $DB->insert_record('user_info_data', $data); + } + } +} + +function block_course_overview_get_child_shortnames($courseid) { + global $COURSE, $DB, $OUTPUT; + + $sql = "SELECT c.shortname + FROM {enrol} AS e + JOIN {course} AS c ON (c.id = e.customint1) + WHERE e.courseid = :courseid AND e.enrol = :method ORDER BY e.sortorder"; + $params = array('method' => 'meta', 'courseid' => $courseid); + if ($results = $DB->get_records_sql($sql, $params)) { + $shortnames = array(); + foreach ($results as $res) { + $shortnames[] = $res->shortname; + } + $total = count($shortnames); + $suffix = ''; + if ($total > 10) { + $shortnames = array_slice($shortnames, 0, 10); + $diff = $total - count($shortnames); + $plural = $diff > 1 ? 's' : ''; + $suffix = " (and $diff other$plural)"; + } + $shortnames = 'includes '.implode('; ', $shortnames).$suffix; + } + + return isset($shortnames) ? $shortnames : false; +} + +function block_course_overview_get_sorted_courses() { + global $USER; + + $limit = 71; //TODO: Make this a block setting + if (isset($USER->profile['mynumber']) && intval($USER->profile['mynumber']) > 0) { + $limit = intval($USER->profile['mynumber']); + } else { + $USER->profile['mynumber'] = 0; + } + + $courses = enrol_get_my_courses('id, shortname, fullname, modinfo'); + $site = get_site(); + + if (array_key_exists($site->id,$courses)) { + unset($courses[$site->id]); + } + + foreach ($courses as $c) { + if (isset($USER->lastcourseaccess[$c->id])) { + $courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id]; + } else { + $courses[$c->id]->lastaccess = 0; + } + } + + $order = array(); + if (isset($USER->profile['myorder'])) { + $order = explode(',', $USER->profile['myorder']); + } + + $courses_sorted = array(); + + //unsorted courses top of the list + foreach ($courses as $c) { + if (count($courses_sorted) >= $limit) { + break; + } + if (!in_array($c->id, $order)) { + $courses_sorted[$c->id] = $c; + } + } + + //get courses in sort order into list + foreach ($order as $o) { + if (count($courses_sorted) >= $limit) { + break; + } + if (isset($courses[intval($o)])) { + $courses_sorted[$o] = $courses[$o]; + } + } + + //append the remaining courses onto the end of the list + foreach ($courses as $c) { + if (count($courses_sorted) >= $limit) { + break; + } + if (!isset($courses_sorted[$c->id])) { + $courses_sorted[$c->id] = $c; + } + } + + return array($courses_sorted, count($courses)); +} diff --git a/blocks/course_overview/module.js b/blocks/course_overview/module.js new file mode 100644 index 00000000000..6a6536d56e9 --- /dev/null +++ b/blocks/course_overview/module.js @@ -0,0 +1,226 @@ +M.block_course_overview = {} + +M.block_course_overview.add_handles = function(Y) { + M.block_course_overview.Y = Y; + YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', 'dd-plugin', function(Y) { + //Static Vars + var goingUp = false, lastY = 0; + + var list = Y.Node.all('#course_list .coursebox'); + list.each(function(v, k) { + var dd = new Y.DD.Drag({ + node: v, + target: { + padding: '0 0 0 20' + } + }).plug(Y.Plugin.DDProxy, { + moveOnEnd: false + }).plug(Y.Plugin.DDConstrained, { + constrain2node: '#course_list' + }); + dd.addHandle('.course_title .move'); + }); + + var drops = Y.Node.all('#coursebox'); + drops.each(function(v, k) { + var tar = new Y.DD.Drop({ + node: v + }); + }); + + Y.DD.DDM.on('drag:start', function(e) { + //Get our drag object + var drag = e.target; + //Set some styles here + drag.get('node').setStyle('opacity', '.25'); + drag.get('dragNode').addClass('block_course_overview'); + drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML')); + drag.get('dragNode').setStyles({ + opacity: '.5', + borderColor: drag.get('node').getStyle('borderColor'), + backgroundColor: drag.get('node').getStyle('backgroundColor') + }); + }); + + Y.DD.DDM.on('drag:end', function(e) { + var drag = e.target; + //Put our styles back + drag.get('node').setStyles({ + visibility: '', + opacity: '1' + }); + M.block_course_overview.save(Y); + }); + + Y.DD.DDM.on('drag:drag', function(e) { + //Get the last y point + var y = e.target.lastXY[1]; + //is it greater than the lastY var? + if (y < lastY) { + //We are going up + goingUp = true; + } else { + //We are going down. + goingUp = false; + } + //Cache for next check + lastY = y; + }); + + Y.DD.DDM.on('drop:over', function(e) { + //Get a reference to our drag and drop nodes + var drag = e.drag.get('node'), + drop = e.drop.get('node'); + + //Are we dropping on a li node? + if (drop.hasClass('coursebox')) { + //Are we not going up? + if (!goingUp) { + drop = drop.get('nextSibling'); + } + //Add the node to this list + e.drop.get('node').get('parentNode').insertBefore(drag, drop); + //Resize this nodes shim, so we can drop on it later. + e.drop.sizeShim(); + } + }); + + Y.DD.DDM.on('drag:drophit', function(e) { + var drop = e.drop.get('node'), + drag = e.drag.get('node'); + + //if we are not on an li, we must have been dropped on a ul + if (!drop.hasClass('coursebox')) { + if (!drop.contains(drag)) { + drop.appendChild(drag); + } + } + }); + }); +} + +M.block_course_overview.save = function() { + var Y = M.block_course_overview.Y; + var sortorder = Y.one('#course_list').get('children').getAttribute('id'); + for (var i = 0; i < sortorder.length; i++) { + sortorder[i] = sortorder[i].substring(7); + } + var params = { + sesskey : M.cfg.sesskey, + sortorder : sortorder + }; + Y.io(M.cfg.wwwroot+'/blocks/course_overview/save.php', { + method: 'POST', + data: build_querystring(params), + context: this + }); +} + +/** + * Init a collapsible region, see print_collapsible_region in weblib.php + * @param {YUI} Y YUI3 instance with all libraries loaded + * @param {String} id the HTML id for the div. + * @param {String} userpref the user preference that records the state of this box. false if none. + * @param {String} strtooltip + */ +M.block_course_overview.collapsible = function(Y, id, userpref, strtooltip) { + if (userpref) { + M.block_course_overview.userpref = true; + } + Y.use('anim', function(Y) { + new M.block_course_overview.CollapsibleRegion(Y, id, userpref, strtooltip); + }); +}; + +/** + * Object to handle a collapsible region : instantiate and forget styled object + * + * @class + * @constructor + * @param {YUI} Y YUI3 instance with all libraries loaded + * @param {String} id The HTML id for the div. + * @param {String} userpref The user preference that records the state of this box. false if none. + * @param {String} strtooltip + */ +M.block_course_overview.CollapsibleRegion = function(Y, id, userpref, strtooltip) { + // Record the pref name + this.userpref = userpref; + + // Find the divs in the document. + this.div = Y.one('#'+id); + + // Get the caption for the collapsible region + var caption = this.div.one('#'+id + '_caption'); + caption.setAttribute('title', strtooltip); + + // Create a link + var a = Y.Node.create(''); + // Create a local scoped lamba function to move nodes to a new link + var movenode = function(node){ + node.remove(); + a.append(node); + }; + // Apply the lamba function on each of the captions child nodes + caption.get('children').each(movenode, this); + caption.prepend(a); + + // Get the height of the div at this point before we shrink it if required + var height = this.div.get('offsetHeight'); + if (this.div.hasClass('collapsed')) { + // Shrink the div as it is collapsed by default + this.div.setStyle('height', caption.get('offsetHeight')+'px'); + } + + // Create the animation. + var animation = new Y.Anim({ + node: this.div, + duration: 0.3, + easing: Y.Easing.easeBoth, + to: {height:caption.get('offsetHeight')}, + from: {height:height} + }); + + // Handler for the animation finishing. + animation.on('end', function() { + this.div.toggleClass('collapsed'); + }, this); + + // Hook up the event handler. + caption.on('click', function(e, animation) { + e.preventDefault(); + // Animate to the appropriate size. + if (animation.get('running')) { + animation.stop(); + } + animation.set('reverse', this.div.hasClass('collapsed')); + // Update the user preference. + if (this.userpref) { + M.util.set_user_preference(this.userpref, !this.div.hasClass('collapsed')); + } + animation.run(); + }, this, animation); +}; + +M.block_course_overview.userpref = false; + +/** + * The user preference that stores the state of this box. + * @property userpref + * @type String + */ +M.block_course_overview.CollapsibleRegion.prototype.userpref = null; + +/** + * The key divs that make up this + * @property div + * @type Y.Node + */ +M.block_course_overview.CollapsibleRegion.prototype.div = null; + +/** + * The key divs that make up this + * @property icon + * @type Y.Node + */ +M.block_course_overview.CollapsibleRegion.prototype.icon = null; + diff --git a/blocks/course_overview/move.php b/blocks/course_overview/move.php new file mode 100644 index 00000000000..eba21d55979 --- /dev/null +++ b/blocks/course_overview/move.php @@ -0,0 +1,58 @@ +. + +require_once(dirname(__FILE__) . '/../../config.php'); +require_once(dirname(__FILE__) . '/locallib.php'); +require_once($CFG->dirroot.'/user/profile/lib.php'); + +require_login(); + +$source = required_param('source', PARAM_INT); +$target = required_param('target', PARAM_INT); + +profile_load_custom_fields($USER); + +//get current sortorder +$sortorder = array(); +if (isset($USER->profile['myorder'])) { + $mysortorder = explode(',', $USER->profile['myorder']); +} + +$courses_sorted = block_course_overview_get_sorted_courses(); +$sortorder = array_keys($courses_sorted); + +//now resort based on new weight for chosen course +$neworder = array(); +reset($sortorder); +foreach ($sortorder as $key => $value) { + if ($value == $source) { + unset($sortorder[$key]); + break; + } +} +for ($i = 0; $i <= count($sortorder) + 1; $i++) { + if ($i == $target) { + $neworder[] = $source; + } + if (isset($sortorder[$i])) { + $neworder[] = $sortorder[$i]; + } +} +$neworder = implode(',', $neworder); +block_course_overview_update_myorder($neworder); + +redirect(new moodle_url('/my/index.php')); diff --git a/blocks/course_overview/pix/collapse_all.png b/blocks/course_overview/pix/collapse_all.png new file mode 100644 index 0000000000000000000000000000000000000000..5d285a7d1cb3cb6787d286793ef8c14622e19991 GIT binary patch literal 3077 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 literal 0 HcmV?d00001 diff --git a/blocks/course_overview/pix/colltopics-arrow-down.png b/blocks/course_overview/pix/colltopics-arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..228c390e7ddf2c1c12736f4da1082342ea0dd0f3 GIT binary patch literal 3280 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 IM6N<$f`t{iAOHXW literal 0 HcmV?d00001 diff --git a/blocks/course_overview/renderer.php b/blocks/course_overview/renderer.php new file mode 100644 index 00000000000..dc510d5a3b7 --- /dev/null +++ b/blocks/course_overview/renderer.php @@ -0,0 +1,240 @@ +. + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->dirroot.'/message/lib.php'); + +class block_course_overview_renderer extends plugin_renderer_base { + + public function course_overview($courses, $overviews, $moving = 0) { + global $OUTPUT; + $html = ''; + $config = get_config('block_course_overview'); + + $html .= html_writer::start_tag('div', array('id' => 'course_list')); + $weight = 0; + $keylist = array_keys($courses); + if ($this->page->user_is_editing() && $moving && $keylist[0] != $moving) { + $html .= $this->course_move_target($moving, $weight); + $weight++; + } + foreach ($courses as $course) { + $cursor = ajaxenabled() && !$moving ? ' cursor' : ''; + $html .= $OUTPUT->box_start('coursebox', "course-{$course->id}"); + $html .= html_writer::start_tag('div', array('class' => 'course_title')); + if ($this->page->user_is_editing()) { + // Move icon. + $icon = ajaxenabled() ? 'i/move_2d' : 't/move'; + $control = array('url' => new moodle_url('/my/index.php', array('course_moveid' => $course->id)), + 'icon' => $icon, 'caption' => get_string('move')); + if (ajaxenabled()) { + $html .= html_writer::tag('div', + html_writer::empty_tag('img', + array('src' => $this->pix_url($control['icon'])->out(false), + 'alt' => $control['caption'], 'class' => 'icon cursor', + 'title' => $control['caption']) + ), array('class' => 'move') + ); + } else { + $html .= html_writer::tag('a', + html_writer::empty_tag('img', array('src' => $this->pix_url($control['icon'])->out(false), 'alt' => $control['caption'])), + array('class' => 'icon move','title' => $control['caption'], 'href' => $control['url'])); + } + } + $link = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), $course->fullname); + $html .= $OUTPUT->heading($link, 2, 'title'); + $html .= $OUTPUT->box('', 'flush'); + $html .= html_writer::end_tag('div'); + + if (isset($config->showchildren) && $config->showchildren) { + //list children here + if ($children = block_course_overview_get_child_shortnames($course->id)) { + $html .= html_writer::tag('span', $children, array('class' => 'coursechildren')); + } + } + + if (isset($overviews[$course->id])) { + $html .= $this->activity_display($course->id, $overviews[$course->id]); + } + + $html .= $OUTPUT->box('', 'flush'); + $html .= $OUTPUT->box_end(); + + if ($this->page->user_is_editing() && $moving && $course->id != $moving) { + //check if next is the course we're moving + $okay = true; + if (isset($keylist[$weight])) { + if ($courses[$keylist[$weight]]->id == $moving) { + $okay = false; + } + } + if ($okay) { + $html .= $this->course_move_target($moving, $weight); + } + } + $weight++; + } + $html .= html_writer::end_tag('div'); + + return $html; + } + + protected function course_move_target($cid, $weight) { + $url = new moodle_url('/blocks/course_overview/move.php', array('source' => $cid, 'target' => $weight)); + return html_writer::tag('a', html_writer::tag('span', get_string('movecoursehere', 'block_course_overview'), + array('class' => 'accesshide')), array('href' => $url, 'class' => 'coursemovetarget')); + } + + protected function activity_display($cid, $overview) { + global $OUTPUT; + $output = html_writer::start_tag('div', array('class' => 'activity_info')); + foreach (array_keys($overview) as $module) { + $output .= html_writer::start_tag('div', array('class' => 'activity_overview')); + $url = new moodle_url("/mod/$module/index.php", array('id' => $cid)); + $icontext = html_writer::link($url, $OUTPUT->pix_icon('icon', get_string('modulename', $module), 'mod_'.$module, array('class'=>'icon')).' '); + if (get_string_manager()->string_exists("activity_$module", 'block_course_overview')) { + $icontext .= get_string("activity_$module", 'block_course_overview'); + } else { + $icontext .= get_string("activityoverview", 'block_course_overview', $module); + } + + //add collapsible region with overview text in it + $output .= $this->collapsible_region($overview[$module], '', 'region_'.$cid.'_'.$module, $icontext, '', true); + + $output .= html_writer::end_tag('div'); + } + $output .= html_writer::end_tag('div'); + return $output; + } + + public function editing_bar_head($max = 0) { + global $OUTPUT, $USER; + $output = $OUTPUT->box_start('notice'); + + $options = array('0' => get_string('alwaysshowall', 'block_course_overview')); + for ($i = 1; $i <= $max; $i++) { + $options[$i] = $i; + } + $url = new moodle_url('/my/index.php'); + $select = new single_select($url, 'mynumber', $options, $USER->profile['mynumber'], array()); + $select->set_label(get_string('numtodisplay', 'block_course_overview')); + $output .= $OUTPUT->render($select); + + $output .= $OUTPUT->box_end(); + return $output; + } + + public function hidden_courses($total) { + global $OUTPUT; + if ($total <= 0) { + return; + } + $output = $OUTPUT->box_start('notice'); + $plural = $total > 1 ? 'plural' : ''; + $output .= get_string('hiddencoursecount'.$plural, 'block_course_overview', $total); + $output .= $OUTPUT->box_end(); + return $output; + } + + protected function collapsible_region($contents, $classes, $id, $caption, $userpref = '', $default = false) { + $output = $this->collapsible_region_start($classes, $id, $caption, $userpref, $default); + $output .= $contents; + $output .= $this->collapsible_region_end(); + + return $output; + } + + /** + * Print (or return) the start of a collapsible region, that has a caption that can + * be clicked to expand or collapse the region. If JavaScript is off, then the region + * will always be expanded. + * + * @param string $classes class names added to the div that is output. + * @param string $id id added to the div that is output. Must not be blank. + * @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract. + * @param string $userpref the name of the user preference that stores the user's preferred default state. + * (May be blank if you do not wish the state to be persisted. + * @param boolean $default Initial collapsed state to use if the user_preference it not set. + * @param boolean $return if true, return the HTML as a string, rather than printing it. + */ + protected function collapsible_region_start($classes, $id, $caption, $userpref = '', $default = false) { + global $CFG, $PAGE, $OUTPUT; + + // Work out the initial state. + if (!empty($userpref) and is_string($userpref)) { + user_preference_allow_ajax_update($userpref, PARAM_BOOL); + $collapsed = get_user_preferences($userpref, $default); + } else { + $collapsed = $default; + $userpref = false; + } + + if ($collapsed) { + $classes .= ' collapsed'; + } + + $output = ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; + $output .= $caption . ' '; + $output .= '
'; + $this->page->requires->js_init_call('M.block_course_overview.collapsible', array($id, $userpref, get_string('clicktohideshow'))); + + return $output; + } + + /** + * Close a region started with print_collapsible_region_start. + * + * @param boolean $return if true, return the HTML as a string, rather than printing it. + */ + protected function collapsible_region_end() { + $output = '
'; + return $output; + } + + public function welcome_area() { + global $OUTPUT, $USER; + $output = $OUTPUT->box_start('welcome_area'); + + $picture = $OUTPUT->user_picture($USER, array('size' => 75, 'class' => 'welcome_userpicture')); + $output .= html_writer::tag('div', $picture, array('class' => 'profilepicture')); + + $output .= $OUTPUT->box_start('welcome_message'); + $output .= $OUTPUT->heading(get_string('welcome', 'block_course_overview', $USER->firstname)); + + //messages + $count = message_count_unread_messages($USER); + $plural = 's'; + if ($count > 0) { + $output .= get_string('you_have_messages', 'block_course_overview', $count); + } else { + $output .= get_string('you_have_no_messages', 'block_course_overview'); + if ($count == 1) { + $plural = ''; + } + } + $output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview')); + $output .= $OUTPUT->box_end(); + $output .= $OUTPUT->box('', 'flush'); + $output .= $OUTPUT->box_end(); + + return $output; + } +} diff --git a/blocks/course_overview/save.php b/blocks/course_overview/save.php new file mode 100644 index 00000000000..36841ccac3f --- /dev/null +++ b/blocks/course_overview/save.php @@ -0,0 +1,31 @@ +. + +define('AJAX_SCRIPT', true); + +/** Include config */ +require_once(dirname(__FILE__) . '/../../config.php'); +require_once(dirname(__FILE__) . '/locallib.php'); + +if (!confirm_sesskey()) { + throw new moodle_exception('invalidsesskey', 'error'); +} + +$sortorder = required_param('sortorder', PARAM_INT); +$sortorder = implode(',', $sortorder); + +block_course_overview_update_myorder($sortorder); diff --git a/blocks/course_overview/settings.php b/blocks/course_overview/settings.php new file mode 100644 index 00000000000..facd4395f1c --- /dev/null +++ b/blocks/course_overview/settings.php @@ -0,0 +1,16 @@ +fulltree) { + $configs = array(); + $configs[] = new admin_setting_configcheckbox('showchildren', get_string('showchildren', 'block_course_overview'), + get_string('showchildren_desc', 'block_course_overview'), ''); + $configs[] = new admin_setting_configcheckbox('showwelcomearea', get_string('showwelcomearea', 'block_course_overview'), + get_string('showwelcomearea_desc', 'block_course_overview'), 1); + + foreach ($configs as $config) { + $config->plugin = 'block_course_overview'; + $settings->add($config); + } +} diff --git a/blocks/course_overview/styles.css b/blocks/course_overview/styles.css new file mode 100644 index 00000000000..269c4b7b1df --- /dev/null +++ b/blocks/course_overview/styles.css @@ -0,0 +1,83 @@ +.pagelayout-mydashboard #region-main .region-content .block_course_overview .header, +.pagelayout-mydashboard #region-main .region-content .block_course_overview .block_action, +.pagelayout-mydashboard #region-main .region-content .block_course_overview .commands { + display: none; +} + +.block_course_overview .coursechildren { + font-size: 12px; + font-weight: normal; + font-style: italic; +} + +.block_course_overview .content { + margin-left: 20px; +} + +.block_course_overview .profilepicture { + float: left; +} + +.block_course_overview .welcome_area { + width: 100%; + padding-bottom: 5px; +} + +.block_course_overview .welcome_message { + float: left; + padding: 10px; + vertical-align: middle; + border-collapse: separate; + clear: none; +} + +.block_course_overview h2.title { + float: left; + font-size: 1.5em !important; + margin-bottom: 0; + margin-top: 0; + position: relative; +} + +.block_course_overview .course_title { + position: relative; +} + +.editing .block_course_overview h2.title { + left: 20px; +} + +.editing .block_course_overview .coursebox .cursor { + cursor: move; + margin-bottom: 2px; +} + +.editing .block_course_overview .move { + float: left; + position: absolute; + width: 20px; +} + +.block_course_overview #course_list { + width: 100%; +} + +.block_course_overview div.flush { + clear: both; +} + +.block_course_overview .activity_info { + clear: both; +} + +.block_course_overview .activity_overview { + padding: 2px; +} + +.block_course_overview .singleselect { + text-align: left; + margin: 0; +} + +.block_course_overview .coursemovetarget {display: block;height: 1em;margin-bottom: 1em;border-width: 2px;border-style: dashed;} + diff --git a/blocks/course_overview/version.php b/blocks/course_overview/version.php index 68d118f7a01..a117c9f0633 100644 --- a/blocks/course_overview/version.php +++ b/blocks/course_overview/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX) +$plugin->version = 2012062800; // The current plugin version (Date: YYYYMMDDXX) $plugin->requires = 2012061700; // Requires this Moodle version -$plugin->component = 'block_course_overview'; // Full name of the plugin (used for diagnostics) +$plugin->component = 'block_course_overview'; // Full name of the plugin (used for diagnostics) \ No newline at end of file From 37b5e8fee826a770c65485f2549c0c9996a220b8 Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Thu, 28 Jun 2012 16:35:45 +0800 Subject: [PATCH 021/106] MDL-19430 My Moodle: Polished course_over view code of netspot --- blocks/course_overview/README | 33 --- .../course_overview/block_course_overview.php | 70 ++--- blocks/course_overview/db/install.php | 28 -- blocks/course_overview/db/upgrade.php | 30 --- .../lang/en/block_course_overview.php | 41 ++- blocks/course_overview/locallib.php | 204 +++++++------- blocks/course_overview/move.php | 77 +++--- blocks/course_overview/pix/collapse_all.png | Bin 3077 -> 0 bytes .../pix/colltopics-arrow-current.png | Bin 3168 -> 0 bytes .../pix/colltopics-arrow-down-current.png | Bin 3157 -> 0 bytes .../pix/colltopics-arrow-down.png | Bin 3280 -> 0 bytes .../pix/colltopics-arrow-right.png | Bin 3300 -> 0 bytes blocks/course_overview/pix/expand_all.png | Bin 3066 -> 0 bytes blocks/course_overview/renderer.php | 251 +++++++++++------- blocks/course_overview/save.php | 17 +- blocks/course_overview/settings.php | 39 ++- blocks/course_overview/styles.css | 45 ++-- blocks/course_overview/version.php | 3 +- mod/assign/lang/en/assign.php | 1 + mod/assignment/lang/en/assignment.php | 1 + mod/chat/lang/en/chat.php | 1 + mod/forum/lang/en/forum.php | 1 + mod/quiz/lang/en/quiz.php | 1 + 23 files changed, 462 insertions(+), 381 deletions(-) delete mode 100644 blocks/course_overview/README delete mode 100644 blocks/course_overview/db/install.php delete mode 100644 blocks/course_overview/db/upgrade.php delete mode 100644 blocks/course_overview/pix/collapse_all.png delete mode 100644 blocks/course_overview/pix/colltopics-arrow-current.png delete mode 100644 blocks/course_overview/pix/colltopics-arrow-down-current.png delete mode 100644 blocks/course_overview/pix/colltopics-arrow-down.png delete mode 100644 blocks/course_overview/pix/colltopics-arrow-right.png delete mode 100644 blocks/course_overview/pix/expand_all.png diff --git a/blocks/course_overview/README b/blocks/course_overview/README deleted file mode 100644 index 2aa3aa5e2ed..00000000000 --- a/blocks/course_overview/README +++ /dev/null @@ -1,33 +0,0 @@ -My Course Overview Block for Moodle 2 - -== Main feautres == - -Provides a user configurable list of the courses a user is enrolled in on their My Moodle page. - -The user can set the number of courses to have visible. - -Courses can be reordered in editing mode via drag and drop (with appropriate fallback when ajax disabled for the user). - -Each course can be expanded to show a list of activity icons alerting the user to updated modules or modules requiring attention. - -Optionally can display the shortnames of child courses under the heading of the course (site-wide option). - -Optionally can display a welcome area above the courses that welcomes the user and alerts them of any pending messages. - -== Installing and configuring == - -Place the code for the block under /blocks/my_course_overview and install the block via the Moodle upgrade process. - -== Credits == - -Coding: NetSpot (http://www.netspot.com.au) - -Jointly Funded and Designed by: - - Flinders University (http://www.flinders.edu.au) - - University of Canberra (http://www.canberra.edu.au) - -== See also == - -[https://github.com/netspotau/moodle-block_my_course_overview Github page] - -[[Category: Contributed code]] diff --git a/blocks/course_overview/block_course_overview.php b/blocks/course_overview/block_course_overview.php index 78f45ca3575..34c153dfdd9 100644 --- a/blocks/course_overview/block_course_overview.php +++ b/blocks/course_overview/block_course_overview.php @@ -17,25 +17,29 @@ /** * Course overview block * - * @package block - * @subpackage course_overview + * @package block_course_overview * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once($CFG->dirroot.'/blocks/course_overview/locallib.php'); - +/** + * Course overview block + * + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class block_course_overview extends block_base { /** - * block initializations + * Block initialization */ public function init() { - $this->title = get_string('displaytitle', 'block_course_overview'); + $this->title = get_string('pluginname', 'block_course_overview'); } /** - * block contents + * Return contents of course_overview block * - * @return object + * @return stdClass contents of block */ public function get_content() { global $USER, $CFG, $DB; @@ -53,34 +57,34 @@ class block_course_overview extends block_base { $content = array(); - $moving = optional_param('course_moveid', 0, PARAM_INT); - $updatemynumber = optional_param('mynumber', null, PARAM_INT); - if (!is_null($updatemynumber)) { + $updatemynumber = optional_param('mynumber', -1, PARAM_INT); + if ($updatemynumber >= 0) { block_course_overview_update_mynumber($updatemynumber); } profile_load_custom_fields($USER); - list($courses_sorted, $courses_total) = block_course_overview_get_sorted_courses(); - $overviews = block_course_overview_get_overviews($courses_sorted); + list($sortedcourses, $sitecourses, $totalcourses) = block_course_overview_get_sorted_courses(); + $overviews = block_course_overview_get_overviews($sitecourses); $renderer = $this->page->get_renderer('block_course_overview'); - if (!isset($config->showwelcomearea) || $config->showwelcomearea) { - $this->content->text = $renderer->welcome_area(); + if (!empty($config->showwelcomearea)) { + require_once($CFG->dirroot.'/message/lib.php'); + $msgcount = message_count_unread_messages(); + $this->content->text = $renderer->welcome_area($msgcount); } - //number of sites to display - if ($this->page->user_is_editing()) { - $count = count(enrol_get_my_courses('id')); - $this->content->text .= $renderer->editing_bar_head($count); + // Number of sites to display. + if ($this->page->user_is_editing() && empty($config->forcedefaultmaxcourses)) { + $this->content->text .= $renderer->editing_bar_head($totalcourses); } - if (empty($courses_sorted)) { + if (empty($sortedcourses)) { $this->content->text .= get_string('nocourses','my'); } else { - //for each course, build category cache - $this->content->text .= $renderer->course_overview($courses_sorted, $overviews, $moving); - $this->content->text .= $renderer->hidden_courses($courses_total - count($courses_sorted)); - if ($this->page->user_is_editing() && ajaxenabled() && !$moving) { + // For each course, build category cache. + $this->content->text .= $renderer->course_overview($sortedcourses, $overviews); + $this->content->text .= $renderer->hidden_courses($totalcourses - count($sortedcourses)); + if ($this->page->user_is_editing() && ajaxenabled()) { $this->page->requires->js_init_call('M.block_course_overview.add_handles'); } } @@ -89,7 +93,7 @@ class block_course_overview extends block_base { } /** - * allow the block to have a configuration page + * Allow the block to have a configuration page * * @return boolean */ @@ -98,7 +102,7 @@ class block_course_overview extends block_base { } /** - * locations where block can be displayed + * Locations where block can be displayed * * @return array */ @@ -106,12 +110,14 @@ class block_course_overview extends block_base { return array('my-index' => true); } - public function instance_can_be_hidden() { - return false; - } - + /** + * Sets block header to be hidden or visible + * + * @return bool if true then header will be visible. + */ public function hide_header() { - return true; + // Hide header if welcome area is show. + $config = get_config('block_course_overview'); + return !empty($config->showwelcomearea); } -} -?> +} \ No newline at end of file diff --git a/blocks/course_overview/db/install.php b/blocks/course_overview/db/install.php deleted file mode 100644 index 67d6914cf8f..00000000000 --- a/blocks/course_overview/db/install.php +++ /dev/null @@ -1,28 +0,0 @@ -get_record('user_info_field', array('shortname' => 'mynumber'))) { - $field = new stdClass(); - $field->shortname = 'mynumber'; - $field->name = 'Number of courses on My Moodle'; - $field->datatype = 'text'; - $field->visible = 1; - $field->categoryid = 1; - - $DB->insert_record('user_info_field', $field); - } - - if (!$DB->get_record('user_info_field', array('shortname' => 'myorder'))) { - $field = new stdClass(); - $field->shortname = 'myorder'; - $field->name = 'Order of courses on My Moodle'; - $field->datatype = 'text'; - $field->visible = 0; - $field->categoryid = 1; - - $DB->insert_record('user_info_field', $field); - } -} \ No newline at end of file diff --git a/blocks/course_overview/db/upgrade.php b/blocks/course_overview/db/upgrade.php deleted file mode 100644 index f59f7a52468..00000000000 --- a/blocks/course_overview/db/upgrade.php +++ /dev/null @@ -1,30 +0,0 @@ -get_record('user_info_field', array('shortname' => 'mynumber'))) { - $field = new stdClass(); - $field->shortname = 'mynumber'; - $field->name = 'Number of courses on My Moodle'; - $field->datatype = 'text'; - $field->visible = 1; - $field->categoryid = 1; - - $DB->insert_record('user_info_field', $field); - } - - if (!$DB->get_record('user_info_field', array('shortname' => 'myorder'))) { - $field = new stdClass(); - $field->shortname = 'myorder'; - $field->name = 'Order of courses on My Moodle'; - $field->datatype = 'text'; - $field->visible = 0; - $field->categoryid = 1; - - $DB->insert_record('user_info_field', $field); - } - upgrade_block_savepoint(true, 2012062800, 'course_overview'); - } - return true; -} diff --git a/blocks/course_overview/lang/en/block_course_overview.php b/blocks/course_overview/lang/en/block_course_overview.php index f7b2063b9aa..99dc733b401 100644 --- a/blocks/course_overview/lang/en/block_course_overview.php +++ b/blocks/course_overview/lang/en/block_course_overview.php @@ -1,15 +1,37 @@ . + +/** + * Lang strings for course_overview block + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ $string['pluginname'] = 'Course overview'; -$string['activity_assignment'] = 'You have assignments that need attention'; -$string['activity_forum'] = 'There are new forum posts'; -$string['activity_quiz'] = 'You have quizzes that are due'; $string['activityoverview'] = 'You have {$a}s that need attention'; $string['alwaysshowall'] = 'Always Show All'; $string['collapseall'] = 'Collapse All Course Lists'; $string['configotherexpanded'] = 'If enabled, Other Courses will be expanded by default unless overriden by user preferences.'; $string['configpreservestates'] = 'If enabled, the collapsed/expanded states set by the user are stored and used on each load.'; -$string['displaytitle'] = 'learnonline: My Home'; +$string['defaultmaxcourses'] = 'Default maximum courses'; +$string['defaultmaxcoursesdesc'] = 'Maximum courses which should be displayed on course overview block, 0 will show all courses'; $string['expandall'] = 'Expand All Course Lists'; +$string['forcedefaultmaxcourses'] = 'Force maximum courses'; +$string['forcedefaultmaxcoursesdesc'] = 'If set then user will not be able to change his/her personal setting'; $string['hiddencoursecount'] = 'You have {$a} hidden course'; $string['hiddencoursecountplural'] = 'You have {$a} hidden courses'; $string['movecoursehere'] = 'Move course here'; @@ -18,11 +40,14 @@ $string['otherexpanded'] = 'Other Courses Expanded'; $string['preservestates'] = 'Preserve Expanded States'; $string['message'] = 'message'; $string['messages'] = 'messages'; +$string['shortnameprefix'] = 'Includes {$a}'; +$string['shortnamesufixsingular'] = ' (and {$a} other)'; +$string['shortnamesufixprural'] = ' (and {$a} others)'; $string['showchildren'] = 'Show Children'; -$string['showchildren_desc'] = 'Should child courses be listed underneath the main course title?'; +$string['showchildrendesc'] = 'Should child courses be listed underneath the main course title?'; $string['showwelcomearea'] = 'Show welcome area'; -$string['showwelcomearea_desc'] = 'Show the welcome area above the course list?'; +$string['showwelcomeareadesc'] = 'Show the welcome area above the course list?'; $string['view_edit_profile'] = '(View and edit your profile.)'; $string['welcome'] = 'Welcome {$a}'; -$string['you_have_messages'] = 'You have {$a} unread '; -$string['you_have_no_messages'] = 'You have no unread '; +$string['youhavemessages'] = 'You have {$a} unread '; +$string['youhavenomessages'] = 'You have no unread '; \ No newline at end of file diff --git a/blocks/course_overview/locallib.php b/blocks/course_overview/locallib.php index fd7fda67c1f..45d5747c897 100644 --- a/blocks/course_overview/locallib.php +++ b/blocks/course_overview/locallib.php @@ -1,5 +1,4 @@ . +/** + * Helper functions for course_overview block + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Display overview for courses + * + * @param array $courses courses for which overview needs to be shown + * @return array html overview + */ function block_course_overview_get_overviews($courses) { - global $CFG, $USER, $DB, $OUTPUT; $htmlarray = array(); - if ($modules = $DB->get_records('modules')) { - foreach ($modules as $mod) { - if (file_exists(dirname(__FILE__).'/../../mod/'.$mod->name.'/lib.php')) { - include_once(dirname(__FILE__).'/../../mod/'.$mod->name.'/lib.php'); - $fname = $mod->name.'_print_overview'; - if (function_exists($fname)) { - $fname($courses,$htmlarray); - } - } + if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { + foreach ($modules as $fname) { + $fname($courses,$htmlarray); } } return $htmlarray; } +/** + * Sets user preference for maximum courses to be displayed in course_overview block + * + * @param int $number maximum courses which should be visible + */ function block_course_overview_update_mynumber($number) { - global $DB, $USER; - if ($field = $DB->get_record('user_info_field', array('shortname' => 'mynumber'))) { - if ($data = $DB->get_record('user_info_data', array('fieldid' => $field->id, 'userid' => $USER->id))) { - $data->data = $number; - $DB->update_record('user_info_data', $data); - } else { - $data = new stdClass(); - $data->fieldid = $field->id; - $data->userid = $USER->id; - $data->data = $number; - $DB->insert_record('user_info_data', $data); - } - } + set_user_preference('course_overview_number_of_courses', $number); } +/** + * Sets user course sorting preference in course_overview block + * + * @param array $sortorder sort order of course + */ function block_course_overview_update_myorder($sortorder) { - global $DB, $USER; - if ($field = $DB->get_record('user_info_field', array('shortname' => 'myorder'))) { - if ($data = $DB->get_record('user_info_data', array('fieldid' => $field->id, 'userid' => $USER->id))) { - - $oldlist = explode(',', $data->data); - $newlist = explode(',', $sortorder); - foreach ($oldlist as $oldentry) { - if (!in_array($oldentry, $newlist)) { - $newlist[] = $oldentry; - } - } - $sortorder = implode(',', $newlist); - - $data->data = $sortorder; - $DB->update_record('user_info_data', $data); - } else { - $data = new stdClass(); - $data->fieldid = $field->id; - $data->userid = $USER->id; - $data->data = $sortorder; - $DB->insert_record('user_info_data', $data); - } - } + set_user_preference('course_overview_course_order', serialize($sortorder)); } +/** + * Returns shortname of activities in course + * + * @param int $courseid id of course for which activity shortname is needed + * @return string|bool list of child shortname + */ function block_course_overview_get_child_shortnames($courseid) { - global $COURSE, $DB, $OUTPUT; + global $DB; + $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); + $sql = "SELECT c.id, c.shortname, $ctxselect + FROM {enrol} e + JOIN {course} c ON (c.id = e.customint1) + JOIN {context} ctx ON (ctx.instanceid = e.customint1) + WHERE e.courseid = :courseid AND e.enrol = :method AND ctx.contextlevel = :contextlevel ORDER BY e.sortorder"; + $params = array('method' => 'meta', 'courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE); - $sql = "SELECT c.shortname - FROM {enrol} AS e - JOIN {course} AS c ON (c.id = e.customint1) - WHERE e.courseid = :courseid AND e.enrol = :method ORDER BY e.sortorder"; - $params = array('method' => 'meta', 'courseid' => $courseid); if ($results = $DB->get_records_sql($sql, $params)) { $shortnames = array(); + // Preload the context we will need it to format the category name shortly. foreach ($results as $res) { - $shortnames[] = $res->shortname; + context_helper::preload_from_record($res); + $context = context_course::instance($res->id); + $shortnames[] = format_string($res->shortname, true, $context); } $total = count($shortnames); $suffix = ''; if ($total > 10) { $shortnames = array_slice($shortnames, 0, 10); $diff = $total - count($shortnames); - $plural = $diff > 1 ? 's' : ''; - $suffix = " (and $diff other$plural)"; + if ($diff > 1) { + $suffix = get_string('shortnamesufixprural', 'block_course_overview', $diff); + } else { + $suffix = get_string('shortnamesufixsingular', 'block_course_overview', $diff); + } } - $shortnames = 'includes '.implode('; ', $shortnames).$suffix; + $shortnames = get_string('shortnameprefix', 'block_course_overview', implode('; ', $shortnames)); + $shortnames .= $suffix; } return isset($shortnames) ? $shortnames : false; } +/** + * Returns maximum number of courses which will be displayed in course_overview block + * + * @return int maximum number of courses + */ +function block_course_overview_get_max_user_courses() { + // Get block configuration + $config = get_config('block_course_overview'); + $limit = $config->defaultmaxcourses; + + // If max course is not set then try get user preference + if (empty($config->forcedefaultmaxcourses)) { + $limit = get_user_preferences('course_overview_number_of_courses', $limit); + } + return $limit; +} + +/** + * Return sorted list of user courses + * + * @return array list of sorted courses and count of courses. + */ function block_course_overview_get_sorted_courses() { global $USER; - $limit = 71; //TODO: Make this a block setting - if (isset($USER->profile['mynumber']) && intval($USER->profile['mynumber']) > 0) { - $limit = intval($USER->profile['mynumber']); - } else { - $USER->profile['mynumber'] = 0; - } + $limit = block_course_overview_get_max_user_courses(); $courses = enrol_get_my_courses('id, shortname, fullname, modinfo'); $site = get_site(); @@ -126,42 +140,54 @@ function block_course_overview_get_sorted_courses() { } } - $order = array(); - if (isset($USER->profile['myorder'])) { - $order = explode(',', $USER->profile['myorder']); + // Get remote courses. + $remotecourses = array(); + if (is_enabled_auth('mnet')) { + $remotecourses = get_my_remotecourses(); + } + // Remote courses will have -ve remoteid as key, so it can be differentiated from normal courses + foreach ($remotecourses as $id => $val) { + $remoteid = $val->remoteid * -1; + $val->id = $remoteid; + $courses[$remoteid] = $val; } - $courses_sorted = array(); + $order = array(); + if (!is_null($usersortorder = get_user_preferences('course_overview_course_order'))) { + $order = unserialize($usersortorder); + } - //unsorted courses top of the list + $sortedcourses = array(); + $counter = 0; + // Get courses in sort order into list. + foreach ($order as $key => $cid) { + if (($counter >= $limit) && ($limit != 0)) { + break; + } + + // Make sure user is still enroled. + if (isset($courses[$cid])) { + $sortedcourses[$cid] = $courses[$cid]; + $counter++; + } + } + // Append unsorted courses if limit allows foreach ($courses as $c) { - if (count($courses_sorted) >= $limit) { + if (($limit != 0) && ($counter >= $limit)) { break; } if (!in_array($c->id, $order)) { - $courses_sorted[$c->id] = $c; + $sortedcourses[$c->id] = $c; + $counter++; } } - //get courses in sort order into list - foreach ($order as $o) { - if (count($courses_sorted) >= $limit) { - break; - } - if (isset($courses[intval($o)])) { - $courses_sorted[$o] = $courses[$o]; + // From list extract site courses for overview + $sitecourses = array(); + foreach ($sortedcourses as $key => $course) { + if ($course->id > 0) { + $sitecourses[$key] = $course; } } - - //append the remaining courses onto the end of the list - foreach ($courses as $c) { - if (count($courses_sorted) >= $limit) { - break; - } - if (!isset($courses_sorted[$c->id])) { - $courses_sorted[$c->id] = $c; - } - } - - return array($courses_sorted, count($courses)); + return array($sortedcourses, $sitecourses, count($courses)); } diff --git a/blocks/course_overview/move.php b/blocks/course_overview/move.php index eba21d55979..8cb7b1b5b4f 100644 --- a/blocks/course_overview/move.php +++ b/blocks/course_overview/move.php @@ -1,5 +1,4 @@ . +/** + * Move/order course functionality for course_overview block. + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once(dirname(__FILE__) . '/../../config.php'); require_once(dirname(__FILE__) . '/locallib.php'); -require_once($CFG->dirroot.'/user/profile/lib.php'); +require_sesskey(); require_login(); $source = required_param('source', PARAM_INT); -$target = required_param('target', PARAM_INT); +$move = required_param('move', PARAM_INT); -profile_load_custom_fields($USER); - -//get current sortorder -$sortorder = array(); -if (isset($USER->profile['myorder'])) { - $mysortorder = explode(',', $USER->profile['myorder']); -} - -$courses_sorted = block_course_overview_get_sorted_courses(); +list($courses_sorted, $sitecourses, $coursecount) = block_course_overview_get_sorted_courses(); $sortorder = array_keys($courses_sorted); - -//now resort based on new weight for chosen course +// Now resort based on new weight for chosen course. $neworder = array(); -reset($sortorder); -foreach ($sortorder as $key => $value) { - if ($value == $source) { - unset($sortorder[$key]); - break; - } -} -for ($i = 0; $i <= count($sortorder) + 1; $i++) { - if ($i == $target) { - $neworder[] = $source; - } - if (isset($sortorder[$i])) { - $neworder[] = $sortorder[$i]; - } -} -$neworder = implode(',', $neworder); -block_course_overview_update_myorder($neworder); +$sourcekey = array_search($source, $sortorder); +if ($sourcekey === false) { + print_error("invalidcourseid", null, null, $source); +} + +$destination = $sourcekey + $move; +if ($destination < 0) { + print_error("listcantmoveup"); +} else if ($destination >= count($courses_sorted)) { + print_error("listcantmovedown"); +} + +// Create neworder list for courses. +unset($sortorder[$sourcekey]); +if ($move == -1) { + if ($destination > 0) { + $neworder = array_slice($sortorder, 0, $destination, true); + } + $neworder[] = $source; + $remaningcourses = array_slice($sortorder, $destination); + foreach ($remaningcourses as $courseid) { + $neworder[] = $courseid; + } +} else if (($move == 1)) { + $neworder = array_slice($sortorder, 0, $destination); + $neworder[] = $source; + if (($destination) < count($courses_sorted)) { + $remaningcourses = array_slice($sortorder, $destination); + foreach ($remaningcourses as $courseid) { + $neworder[] = $courseid; + } + } +} + +block_course_overview_update_myorder($neworder); redirect(new moodle_url('/my/index.php')); diff --git a/blocks/course_overview/pix/collapse_all.png b/blocks/course_overview/pix/collapse_all.png deleted file mode 100644 index 5d285a7d1cb3cb6787d286793ef8c14622e19991..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3077 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 diff --git a/blocks/course_overview/pix/colltopics-arrow-down.png b/blocks/course_overview/pix/colltopics-arrow-down.png deleted file mode 100644 index 228c390e7ddf2c1c12736f4da1082342ea0dd0f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3280 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 IM6N<$f`t{iAOHXW diff --git a/blocks/course_overview/renderer.php b/blocks/course_overview/renderer.php index dc510d5a3b7..4d9f4fa5c08 100644 --- a/blocks/course_overview/renderer.php +++ b/blocks/course_overview/renderer.php @@ -1,5 +1,4 @@ . +/** + * course_overview block rendrer + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ defined('MOODLE_INTERNAL') || die; -require_once($CFG->dirroot.'/message/lib.php'); - +/** + * Course_overview block rendrer + * + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class block_course_overview_renderer extends plugin_renderer_base { - public function course_overview($courses, $overviews, $moving = 0) { - global $OUTPUT; + /** + * Construct contents of course_overview block + * + * @param array $courses list of courses in sorted order + * @param array $overviews list of course overviews + * @return string html to be displayed in course_overview block + */ + public function course_overview($courses, $overviews) { $html = ''; $config = get_config('block_course_overview'); $html .= html_writer::start_tag('div', array('id' => 'course_list')); - $weight = 0; - $keylist = array_keys($courses); - if ($this->page->user_is_editing() && $moving && $keylist[0] != $moving) { - $html .= $this->course_move_target($moving, $weight); - $weight++; - } - foreach ($courses as $course) { - $cursor = ajaxenabled() && !$moving ? ' cursor' : ''; - $html .= $OUTPUT->box_start('coursebox', "course-{$course->id}"); - $html .= html_writer::start_tag('div', array('class' => 'course_title')); - if ($this->page->user_is_editing()) { - // Move icon. - $icon = ajaxenabled() ? 'i/move_2d' : 't/move'; - $control = array('url' => new moodle_url('/my/index.php', array('course_moveid' => $course->id)), - 'icon' => $icon, 'caption' => get_string('move')); - if (ajaxenabled()) { - $html .= html_writer::tag('div', - html_writer::empty_tag('img', - array('src' => $this->pix_url($control['icon'])->out(false), - 'alt' => $control['caption'], 'class' => 'icon cursor', - 'title' => $control['caption']) - ), array('class' => 'move') - ); - } else { - $html .= html_writer::tag('a', - html_writer::empty_tag('img', array('src' => $this->pix_url($control['icon'])->out(false), 'alt' => $control['caption'])), - array('class' => 'icon move','title' => $control['caption'], 'href' => $control['url'])); - } + $courseordernumber = 0; + $maxcourses = count($courses); + // Intialize string/icon etc if user is editing. + $url = null; + $moveicon = null; + $moveup[] = null; + $movedown[] = null; + if ($this->page->user_is_editing()) { + if (ajaxenabled()) { + $moveicon = html_writer::tag('div', + html_writer::empty_tag('img', + array('src' => $this->pix_url('i/move_2d')->out(false), + 'alt' => get_string('move'), 'class' => 'cursor', + 'title' => get_string('move')) + ), array('class' => 'move') + ); + } else { + $url = new moodle_url('/blocks/course_overview/move.php', array('sesskey' => sesskey())); + $moveup['str'] = get_string('moveup'); + $moveup['icon'] = $this->pix_url('t/up'); + $movedown['str'] = get_string('movedown'); + $movedown['icon'] = $this->pix_url('t/down'); } - $link = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), $course->fullname); - $html .= $OUTPUT->heading($link, 2, 'title'); - $html .= $OUTPUT->box('', 'flush'); + } + + foreach ($courses as $key => $course) { + $html .= $this->output->box_start('coursebox', "course-{$course->id}"); + $html .= html_writer::start_tag('div', array('class' => 'course_title')); + // Ajax enabled then add moveicon html + if (!is_null($moveicon)) { + $html .= $moveicon; + } else if (!is_null($url)) { + // Add course id to move link + $url->param('source', $course->id); + $html .= html_writer::start_tag('div', array('class' => 'moveicons')); + // Add an arrow to move course up. + if ($courseordernumber > 0) { + $url->param('move', -1); + $html .= html_writer::link($url, + html_writer::empty_tag('img', array('src' => $moveup['icon'], + 'class' => 'up', 'alt' => $moveup['str'])), + array('title' => $moveup['str'], 'class' => 'moveup')); + } else { + // Add a spacer to keep keep down arrow icons at right position. + $html .= html_writer::empty_tag('img', array('src' => $this->pix_url('t/spacer'), + 'class' => 'moveup spacer')); + } + // Add an arrow to move course down. + if ($courseordernumber <= $maxcourses-2) { + $url->param('move', 1); + $html .= html_writer::link($url, html_writer::empty_tag('img', + array('src' => $movedown['icon'], 'class' => 'down', 'alt' => $movedown['str'])), + array('title' => $movedown['str'], 'class' => 'movedown')); + } + $html .= html_writer::end_tag('div'); + } + + $attributes = array('title' => s($course->fullname)); + if ($course->id > 0) { + $link = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), format_string($course->shortname, true, $course->id), $attributes); + $html .= $this->output->heading($link, 2, 'title'); + } else { + $html .= $this->output->heading(html_writer::link( + new moodle_url('/auth/mnet/jump.php', array('hostid' => $course->hostid, 'wantsurl' => '/course/view.php?id='.$course->remoteid)), + format_string($course->shortname, true, $course->id), $attributes) . ' (' . format_string($course->hostname) . ')', 2, 'title'); + } + $html .= $this->output->box('', 'flush'); $html .= html_writer::end_tag('div'); - if (isset($config->showchildren) && $config->showchildren) { - //list children here + if (!empty($config->showchildren) && ($course->id > 0)) { + // List children here. if ($children = block_course_overview_get_child_shortnames($course->id)) { $html .= html_writer::tag('span', $children, array('class' => 'coursechildren')); } @@ -72,48 +123,36 @@ class block_course_overview_renderer extends plugin_renderer_base { $html .= $this->activity_display($course->id, $overviews[$course->id]); } - $html .= $OUTPUT->box('', 'flush'); - $html .= $OUTPUT->box_end(); - - if ($this->page->user_is_editing() && $moving && $course->id != $moving) { - //check if next is the course we're moving - $okay = true; - if (isset($keylist[$weight])) { - if ($courses[$keylist[$weight]]->id == $moving) { - $okay = false; - } - } - if ($okay) { - $html .= $this->course_move_target($moving, $weight); - } - } - $weight++; + $html .= $this->output->box('', 'flush'); + $html .= $this->output->box_end(); + $courseordernumber++; } $html .= html_writer::end_tag('div'); return $html; } - protected function course_move_target($cid, $weight) { - $url = new moodle_url('/blocks/course_overview/move.php', array('source' => $cid, 'target' => $weight)); - return html_writer::tag('a', html_writer::tag('span', get_string('movecoursehere', 'block_course_overview'), - array('class' => 'accesshide')), array('href' => $url, 'class' => 'coursemovetarget')); - } - + /** + * Coustuct activities overview for a course + * + * @param int $cid course id + * @param array $overview overview of activities in course + * @return string html of activities overview + */ protected function activity_display($cid, $overview) { - global $OUTPUT; $output = html_writer::start_tag('div', array('class' => 'activity_info')); foreach (array_keys($overview) as $module) { $output .= html_writer::start_tag('div', array('class' => 'activity_overview')); $url = new moodle_url("/mod/$module/index.php", array('id' => $cid)); - $icontext = html_writer::link($url, $OUTPUT->pix_icon('icon', get_string('modulename', $module), 'mod_'.$module, array('class'=>'icon')).' '); - if (get_string_manager()->string_exists("activity_$module", 'block_course_overview')) { - $icontext .= get_string("activity_$module", 'block_course_overview'); + $modulename = get_string('modulename', $module); + $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'icon')).' '); + if (get_string_manager()->string_exists("activityoverview", $module)) { + $icontext .= get_string("activityoverview", $module); } else { - $icontext .= get_string("activityoverview", 'block_course_overview', $module); + $icontext .= get_string("activityoverview", 'block_course_overview', $modulename); } - //add collapsible region with overview text in it + // Add collapsible region with overview text in it. $output .= $this->collapsible_region($overview[$module], '', 'region_'.$cid.'_'.$module, $icontext, '', true); $output .= html_writer::end_tag('div'); @@ -122,35 +161,57 @@ class block_course_overview_renderer extends plugin_renderer_base { return $output; } + /** + * Constructs header in editing mode + * + * @param int $max maximum number of courses + * @return string html of header bar. + */ public function editing_bar_head($max = 0) { - global $OUTPUT, $USER; - $output = $OUTPUT->box_start('notice'); + $output = $this->output->box_start('notice'); $options = array('0' => get_string('alwaysshowall', 'block_course_overview')); for ($i = 1; $i <= $max; $i++) { $options[$i] = $i; } $url = new moodle_url('/my/index.php'); - $select = new single_select($url, 'mynumber', $options, $USER->profile['mynumber'], array()); + $select = new single_select($url, 'mynumber', $options, block_course_overview_get_max_user_courses(), array()); $select->set_label(get_string('numtodisplay', 'block_course_overview')); - $output .= $OUTPUT->render($select); + $output .= $this->output->render($select); - $output .= $OUTPUT->box_end(); + $output .= $this->output->box_end(); return $output; } + /** + * Show hidden courses count + * + * @param int $total count of hidden courses + * @return string html + */ public function hidden_courses($total) { - global $OUTPUT; if ($total <= 0) { return; } - $output = $OUTPUT->box_start('notice'); + $output = $this->output->box_start('notice'); $plural = $total > 1 ? 'plural' : ''; $output .= get_string('hiddencoursecount'.$plural, 'block_course_overview', $total); - $output .= $OUTPUT->box_end(); + $output .= $this->output->box_end(); return $output; } + /** + * Creates collapsable region + * + * @param string $contents existing contents + * @param string $classes class names added to the div that is output. + * @param string $id id added to the div that is output. Must not be blank. + * @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract. + * @param string $userpref the name of the user preference that stores the user's preferred default state. + * (May be blank if you do not wish the state to be persisted. + * @param bool $default Initial collapsed state to use if the user_preference it not set. + * @return bool if true, return the HTML as a string, rather than printing it. + */ protected function collapsible_region($contents, $classes, $id, $caption, $userpref = '', $default = false) { $output = $this->collapsible_region_start($classes, $id, $caption, $userpref, $default); $output .= $contents; @@ -169,12 +230,10 @@ class block_course_overview_renderer extends plugin_renderer_base { * @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract. * @param string $userpref the name of the user preference that stores the user's preferred default state. * (May be blank if you do not wish the state to be persisted. - * @param boolean $default Initial collapsed state to use if the user_preference it not set. - * @param boolean $return if true, return the HTML as a string, rather than printing it. + * @param bool $default Initial collapsed state to use if the user_preference it not set. + * @return bool if true, return the HTML as a string, rather than printing it. */ protected function collapsible_region_start($classes, $id, $caption, $userpref = '', $default = false) { - global $CFG, $PAGE, $OUTPUT; - // Work out the initial state. if (!empty($userpref) and is_string($userpref)) { user_preference_allow_ajax_update($userpref, PARAM_BOOL); @@ -202,38 +261,42 @@ class block_course_overview_renderer extends plugin_renderer_base { /** * Close a region started with print_collapsible_region_start. * - * @param boolean $return if true, return the HTML as a string, rather than printing it. + * @return string return the HTML as a string, rather than printing it. */ protected function collapsible_region_end() { $output = '
'; return $output; } - public function welcome_area() { - global $OUTPUT, $USER; - $output = $OUTPUT->box_start('welcome_area'); + /** + * Cretes html for welcome area + * + * @param int $msgcount number of messages + * @return string html string for welcome area. + */ + public function welcome_area($msgcount) { + global $USER; + $output = $this->output->box_start('welcome_area'); - $picture = $OUTPUT->user_picture($USER, array('size' => 75, 'class' => 'welcome_userpicture')); + $picture = $this->output->user_picture($USER, array('size' => 75, 'class' => 'welcome_userpicture')); $output .= html_writer::tag('div', $picture, array('class' => 'profilepicture')); - $output .= $OUTPUT->box_start('welcome_message'); - $output .= $OUTPUT->heading(get_string('welcome', 'block_course_overview', $USER->firstname)); + $output .= $this->output->box_start('welcome_message'); + $output .= $this->output->heading(get_string('welcome', 'block_course_overview', $USER->firstname)); - //messages - $count = message_count_unread_messages($USER); $plural = 's'; - if ($count > 0) { - $output .= get_string('you_have_messages', 'block_course_overview', $count); + if ($msgcount > 0) { + $output .= get_string('youhavemessages', 'block_course_overview', $msgcount); } else { - $output .= get_string('you_have_no_messages', 'block_course_overview'); - if ($count == 1) { + $output .= get_string('youhavenomessages', 'block_course_overview'); + if ($msgcount == 1) { $plural = ''; } } $output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview')); - $output .= $OUTPUT->box_end(); - $output .= $OUTPUT->box('', 'flush'); - $output .= $OUTPUT->box_end(); + $output .= $this->output->box_end(); + $output .= $this->output->box('', 'flush'); + $output .= $this->output->box_end(); return $output; } diff --git a/blocks/course_overview/save.php b/blocks/course_overview/save.php index 36841ccac3f..51a4eb1435b 100644 --- a/blocks/course_overview/save.php +++ b/blocks/course_overview/save.php @@ -1,5 +1,4 @@ . +/** + * Save course order in course_overview block + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ define('AJAX_SCRIPT', true); -/** Include config */ require_once(dirname(__FILE__) . '/../../config.php'); require_once(dirname(__FILE__) . '/locallib.php'); -if (!confirm_sesskey()) { - throw new moodle_exception('invalidsesskey', 'error'); -} +require_sesskey(); +require_login(); -$sortorder = required_param('sortorder', PARAM_INT); -$sortorder = implode(',', $sortorder); +$sortorder = required_param_array('sortorder', PARAM_INT); block_course_overview_update_myorder($sortorder); diff --git a/blocks/course_overview/settings.php b/blocks/course_overview/settings.php index facd4395f1c..2873dd3a6ec 100644 --- a/blocks/course_overview/settings.php +++ b/blocks/course_overview/settings.php @@ -1,16 +1,35 @@ . +/** + * course_overview block settings + * + * @package block_course_overview + * @copyright 2012 Adam Olley + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ defined('MOODLE_INTERNAL') || die; if ($ADMIN->fulltree) { - $configs = array(); - $configs[] = new admin_setting_configcheckbox('showchildren', get_string('showchildren', 'block_course_overview'), - get_string('showchildren_desc', 'block_course_overview'), ''); - $configs[] = new admin_setting_configcheckbox('showwelcomearea', get_string('showwelcomearea', 'block_course_overview'), - get_string('showwelcomearea_desc', 'block_course_overview'), 1); - - foreach ($configs as $config) { - $config->plugin = 'block_course_overview'; - $settings->add($config); - } + $settings->add(new admin_setting_configtext('block_course_overview/defaultmaxcourses', get_string('defaultmaxcourses', 'block_course_overview'), + get_string('defaultmaxcoursesdesc', 'block_course_overview'), 10, PARAM_INT)); + $settings->add(new admin_setting_configcheckbox('block_course_overview/forcedefaultmaxcourses', get_string('forcedefaultmaxcourses', 'block_course_overview'), + get_string('forcedefaultmaxcoursesdesc', 'block_course_overview'), 1, PARAM_INT)); + $settings->add(new admin_setting_configcheckbox('block_course_overview/showchildren', get_string('showchildren', 'block_course_overview'), + get_string('showchildrendesc', 'block_course_overview'), 1, PARAM_INT)); + $settings->add(new admin_setting_configcheckbox('block_course_overview/showwelcomearea', get_string('showwelcomearea', 'block_course_overview'), + get_string('showwelcomeareadesc', 'block_course_overview'), 1, PARAM_INT)); } diff --git a/blocks/course_overview/styles.css b/blocks/course_overview/styles.css index 269c4b7b1df..4d41bb0ab23 100644 --- a/blocks/course_overview/styles.css +++ b/blocks/course_overview/styles.css @@ -1,11 +1,4 @@ -.pagelayout-mydashboard #region-main .region-content .block_course_overview .header, -.pagelayout-mydashboard #region-main .region-content .block_course_overview .block_action, -.pagelayout-mydashboard #region-main .region-content .block_course_overview .commands { - display: none; -} - .block_course_overview .coursechildren { - font-size: 12px; font-weight: normal; font-style: italic; } @@ -14,6 +7,11 @@ margin-left: 20px; } +.block_course_overview .coursebox { + padding: 15px 0px 10px 10px; + width: 98%; +} + .block_course_overview .profilepicture { float: left; } @@ -31,9 +29,8 @@ clear: none; } -.block_course_overview h2.title { +.block_course_overview .content h2.title { float: left; - font-size: 1.5em !important; margin-bottom: 0; margin-top: 0; position: relative; @@ -43,10 +40,6 @@ position: relative; } -.editing .block_course_overview h2.title { - left: 20px; -} - .editing .block_course_overview .coursebox .cursor { cursor: move; margin-bottom: 2px; @@ -54,8 +47,21 @@ .editing .block_course_overview .move { float: left; - position: absolute; - width: 20px; + padding: 2px 10px 0px 0px; +} + +.editing .block_course_overview .moveicons { + display: block; + float: left; +} + +.editing .block_course_overview .moveup { + padding-right: 5px; +} + +.editing .block_course_overview .spacer { + float: left; + width: 14px; } .block_course_overview #course_list { @@ -79,5 +85,10 @@ margin: 0; } -.block_course_overview .coursemovetarget {display: block;height: 1em;margin-bottom: 1em;border-width: 2px;border-style: dashed;} - +.block_course_overview .coursemovetarget { + display: block; + height: 1em; + margin-bottom: 1em; + border-width: 2px; + border-style: dashed; +} \ No newline at end of file diff --git a/blocks/course_overview/version.php b/blocks/course_overview/version.php index a117c9f0633..4208588dab7 100644 --- a/blocks/course_overview/version.php +++ b/blocks/course_overview/version.php @@ -17,8 +17,7 @@ /** * Version details * - * @package block - * @subpackage course_overview + * @package block_course_overview * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php index 47b6d897667..5a28a1f4b74 100644 --- a/mod/assign/lang/en/assign.php +++ b/mod/assign/lang/en/assign.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['activityoverview'] = 'You have assignments that need attention'; $string['addsubmission'] = 'Add submission'; $string['allowsubmissions'] = 'Allow the user to continue making submissions to this assignment.'; $string['allowsubmissionsshort'] = 'Allow submission changes'; diff --git a/mod/assignment/lang/en/assignment.php b/mod/assignment/lang/en/assignment.php index 879840e95a0..98ec8f4ec09 100644 --- a/mod/assignment/lang/en/assignment.php +++ b/mod/assignment/lang/en/assignment.php @@ -23,6 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['activityoverview'] = 'You have assignments that need attention'; $string['allowdeleting'] = 'Allow deleting'; $string['allowdeleting_help'] = 'If enabled, students may delete uploaded files at any time before submitting for grading.'; $string['allowmaxfiles'] = 'Maximum number of uploaded files'; diff --git a/mod/chat/lang/en/chat.php b/mod/chat/lang/en/chat.php index 25b7b6bdf6c..eb0fc057490 100644 --- a/mod/chat/lang/en/chat.php +++ b/mod/chat/lang/en/chat.php @@ -23,6 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['activityoverview'] = 'You have upcoming chat'; $string['ajax'] = 'Version using Ajax'; $string['autoscroll'] = 'Auto scroll'; $string['beep'] = 'beep'; diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index df64fc9d8c8..659ec8b9872 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -23,6 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['activityoverview'] = 'There are new forum posts'; $string['addanewdiscussion'] = 'Add a new discussion topic'; $string['addanewquestion'] = 'Add a new question'; $string['addanewtopic'] = 'Add a new topic'; diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index 629e2db931c..838084654b3 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -25,6 +25,7 @@ $string['accessnoticesheader'] = 'You can preview this quiz, but if this were a real attempt, you would be blocked because:'; $string['action'] = 'Action'; +$string['activityoverview'] = 'You have quizzes that are due'; $string['adaptive'] = 'Adaptive mode'; $string['adaptive_help'] = 'If enabled, multiple responses to a question are allowed within the same attempt at the quiz. So for example if a response is marked as incorrect, the student will be allowed to try again immediately. However, depending on the "Apply penalties" setting, a penalty will usually be subtracted for each wrong attempt.'; $string['addaquestion'] = 'Add a question ...'; From 8a1a951f7c77bf997256044eba67fb38b5ea33c9 Mon Sep 17 00:00:00 2001 From: David Monllao Date: Mon, 16 Jul 2012 14:54:06 +0800 Subject: [PATCH 022/106] MDL-29563 course Hide duplication button in activities without backup2 support - Credit to Mark Nielsen --- course/lib.php | 4 ++-- course/modduplicate.php | 18 ++++++++++++++---- lang/en/moodle.php | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/course/lib.php b/course/lib.php index 838e194f56f..603901d6561 100644 --- a/course/lib.php +++ b/course/lib.php @@ -3291,8 +3291,8 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele ); } - // Duplicate (require both target import caps to be able to duplicate, see modduplicate.php) - if (has_all_capabilities($dupecaps, $coursecontext)) { + // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php) + if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) { $actions[] = new action_link( new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall')), diff --git a/course/modduplicate.php b/course/modduplicate.php index e08ea355faa..b4d593b4e01 100644 --- a/course/modduplicate.php +++ b/course/modduplicate.php @@ -56,6 +56,20 @@ $PAGE->set_pagelayout('incourse'); $output = $PAGE->get_renderer('core', 'backup'); +$a = new stdClass(); +$a->modtype = get_string('modulename', $cm->modname); +$a->modname = format_string($cm->name); + +if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) { + echo $output->header(); + echo $output->notification(get_string('duplicatenosupport', 'core', $a)); + echo $output->continue_button( + new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id)) + ); + echo $output->footer(); + die; +} + // backup the activity $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE, @@ -118,10 +132,6 @@ if (empty($CFG->keeptempdirectoriesonbackup)) { fulldelete($backupbasepath); } -$a = new stdClass(); -$a->modtype = get_string('modulename', $cm->modname); -$a->modname = format_string($cm->name); - echo $output->header(); if ($newcmid) { diff --git a/lang/en/moodle.php b/lang/en/moodle.php index af23c90f27a..1aae903d93e 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -487,6 +487,7 @@ $string['duplicate'] = 'Duplicate'; $string['duplicateconfirm'] = 'Are you sure you want to duplicate {$a->modtype} \'{$a->modname}\' ?'; $string['duplicatecontcourse'] = 'Return to the course'; $string['duplicatecontedit'] = 'Edit the new copy'; +$string['duplicatenosupport'] = '\'{$a->modname}\' activity could not be duplicated because the {$a->modtype} module does not support backup and restore.'; $string['duplicatesuccess'] = '{$a->modtype} \'{$a->modname}\' has been duplicated successfully'; $string['duplicatinga'] = 'Duplicating: {$a}'; $string['edhelpaspellpath'] = 'To use spell-checking within the editor, you MUST have aspell 0.50 or later installed on your server, and you must specify the correct path to access the aspell binary. On Unix/Linux systems, this path is usually /usr/bin/aspell, but it might be something else.'; From 6b4885319b6d2b49088244536ac13299146193fc Mon Sep 17 00:00:00 2001 From: David Monllao Date: Tue, 17 Jul 2012 15:09:19 +0800 Subject: [PATCH 023/106] MDL-29563 course Throwing an exception instead of a message --- course/modduplicate.php | 9 ++------- lang/en/error.php | 1 + lang/en/moodle.php | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/course/modduplicate.php b/course/modduplicate.php index b4d593b4e01..e8c5c1b3a43 100644 --- a/course/modduplicate.php +++ b/course/modduplicate.php @@ -61,13 +61,8 @@ $a->modtype = get_string('modulename', $cm->modname); $a->modname = format_string($cm->name); if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) { - echo $output->header(); - echo $output->notification(get_string('duplicatenosupport', 'core', $a)); - echo $output->continue_button( - new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id)) - ); - echo $output->footer(); - die; + $url = new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id)); + print_error('duplicatenosupport', 'error', $url, $a); } // backup the activity diff --git a/lang/en/error.php b/lang/en/error.php index 7ad032cec31..b9e57071480 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -204,6 +204,7 @@ $string['dmlwriteexception'] = 'Error writing to database'; $string['downgradedcore'] = 'ERROR!!! The code you are using is OLDER than the version that made these databases!'; $string['downloadedfilecheckfailed'] = 'Downloaded file check failed'; $string['duplicatefieldname'] = 'Duplicate field name "{$a}" detected'; +$string['duplicatenosupport'] = '\'{$a->modname}\' activity could not be duplicated because the {$a->modtype} module does not support backup and restore.'; $string['duplicateparaminsql'] = 'ERROR: duplicate parameter name in query'; $string['duplicaterolename'] = 'There is already a role with this name!'; $string['duplicateroleshortname'] = 'There is already a role with this short name!'; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 1aae903d93e..af23c90f27a 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -487,7 +487,6 @@ $string['duplicate'] = 'Duplicate'; $string['duplicateconfirm'] = 'Are you sure you want to duplicate {$a->modtype} \'{$a->modname}\' ?'; $string['duplicatecontcourse'] = 'Return to the course'; $string['duplicatecontedit'] = 'Edit the new copy'; -$string['duplicatenosupport'] = '\'{$a->modname}\' activity could not be duplicated because the {$a->modtype} module does not support backup and restore.'; $string['duplicatesuccess'] = '{$a->modtype} \'{$a->modname}\' has been duplicated successfully'; $string['duplicatinga'] = 'Duplicating: {$a}'; $string['edhelpaspellpath'] = 'To use spell-checking within the editor, you MUST have aspell 0.50 or later installed on your server, and you must specify the correct path to access the aspell binary. On Unix/Linux systems, this path is usually /usr/bin/aspell, but it might be something else.'; From 1e12c1203bd37f1202999eca09e190deb87c35f7 Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Fri, 11 May 2012 10:49:51 +0800 Subject: [PATCH 024/106] MDL-30651 libraries: Replaced deprecated PARAM_INTEGER with PARAM_INT --- admin/filters.php | 2 +- admin/roles/define.php | 2 +- admin/settings/plugins.php | 4 ++-- admin/tool/capability/index.php | 2 +- blocks/community/communitycourse.php | 18 +++++++++--------- blocks/glossary_random/edit_form.php | 2 +- blocks/quiz_results/edit_form.php | 4 ++-- blocks/rss_client/edit_form.php | 2 +- blocks/rss_client/editfeed.php | 4 ++-- blocks/rss_client/managefeeds.php | 4 ++-- blocks/rss_client/viewfeed.php | 4 ++-- blocks/tag_flickr/edit_form.php | 2 +- blocks/tag_youtube/edit_form.php | 2 +- group/externallib.php | 2 +- lib/blocklib.php | 10 +++++----- lib/moodlelib.php | 1 + mod/quiz/attempt.php | 4 ++-- mod/quiz/edit.php | 2 +- mod/quiz/settings.php | 4 ++-- question/type/match/question.php | 2 +- question/type/truefalse/question.php | 2 +- user/externallib.php | 6 +++--- user/selector/lib.php | 6 +++--- 23 files changed, 46 insertions(+), 45 deletions(-) diff --git a/admin/filters.php b/admin/filters.php index 0d7faa3c088..21869d92746 100644 --- a/admin/filters.php +++ b/admin/filters.php @@ -68,7 +68,7 @@ switch ($action) { case 'setstate': - if ($newstate = optional_param('newstate', '', PARAM_INTEGER)) { + if ($newstate = optional_param('newstate', '', PARAM_INT)) { filter_set_global_state($filterpath, $newstate); if ($newstate == TEXTFILTER_DISABLED) { filter_set_applies_to_strings($filterpath, false); diff --git a/admin/roles/define.php b/admin/roles/define.php index d2f4eb5f501..60dbade27b0 100644 --- a/admin/roles/define.php +++ b/admin/roles/define.php @@ -38,7 +38,7 @@ throw new moodle_exception('invalidaccess'); } if ($action != 'add') { - $roleid = required_param('roleid', PARAM_INTEGER); + $roleid = required_param('roleid', PARAM_INT); } else { $roleid = 0; } diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php index 638aa4009b7..ec274335398 100644 --- a/admin/settings/plugins.php +++ b/admin/settings/plugins.php @@ -264,13 +264,13 @@ if ($hassiteconfig) { 'portfolio_moderate_db_threshold', new lang_string('moderatedbsizethreshold', 'portfolio'), new lang_string('moderatedbsizethresholddesc', 'portfolio'), - 20, PARAM_INTEGER, 3)); + 20, PARAM_INT, 3)); $temp->add(new admin_setting_configtext( 'portfolio_high_db_threshold', new lang_string('highdbsizethreshold', 'portfolio'), new lang_string('highdbsizethresholddesc', 'portfolio'), - 50, PARAM_INTEGER, 3)); + 50, PARAM_INT, 3)); $ADMIN->add('portfoliosettings', $temp); $ADMIN->add('portfoliosettings', new admin_externalpage('portfolionew', new lang_string('addnewportfolio', 'portfolio'), $url, 'moodle/site:config', true), '', $url); diff --git a/admin/tool/capability/index.php b/admin/tool/capability/index.php index 7a0f2d64a6e..e7e49d76fbf 100644 --- a/admin/tool/capability/index.php +++ b/admin/tool/capability/index.php @@ -34,7 +34,7 @@ require_capability('moodle/role:manage', $systemcontext); // Get URL parameters. $capability = optional_param('capability', '', PARAM_CAPABILITY); -$roleids = optional_param_array('roles', array('0'), PARAM_INTEGER); +$roleids = optional_param_array('roles', array('0'), PARAM_INT); // Clean the passed in list of role ids. If 'All' selected as an option, or // if none were selected, do all roles. diff --git a/blocks/community/communitycourse.php b/blocks/community/communitycourse.php index dbd9e075d77..3f32ef77f2b 100644 --- a/blocks/community/communitycourse.php +++ b/blocks/community/communitycourse.php @@ -67,8 +67,8 @@ $communitymanager = new block_community_manager(); $renderer = $PAGE->get_renderer('block_community'); /// Check if the page has been called with trust argument -$add = optional_param('add', -1, PARAM_INTEGER); -$confirm = optional_param('confirmed', false, PARAM_INTEGER); +$add = optional_param('add', -1, PARAM_INT); +$confirm = optional_param('confirmed', false, PARAM_INT); if ($add != -1 and $confirm and confirm_sesskey()) { $course = new stdClass(); $course->name = optional_param('coursefullname', '', PARAM_TEXT); @@ -93,8 +93,8 @@ if ($usercandownload and $cancelrestore and confirm_sesskey()) { /// Download $huburl = optional_param('huburl', false, PARAM_URL); -$download = optional_param('download', -1, PARAM_INTEGER); -$downloadcourseid = optional_param('downloadcourseid', '', PARAM_INTEGER); +$download = optional_param('download', -1, PARAM_INT); +$downloadcourseid = optional_param('downloadcourseid', '', PARAM_INT); $coursefullname = optional_param('coursefullname', '', PARAM_ALPHANUMEXT); $backupsize = optional_param('backupsize', 0, PARAM_INT); if ($usercandownload and $download != -1 and !empty($downloadcourseid) and confirm_sesskey()) { @@ -125,8 +125,8 @@ if ($usercandownload and $download != -1 and !empty($downloadcourseid) and confi } /// Remove community -$remove = optional_param('remove', '', PARAM_INTEGER); -$communityid = optional_param('communityid', '', PARAM_INTEGER); +$remove = optional_param('remove', '', PARAM_INT); +$communityid = optional_param('communityid', '', PARAM_INT); if ($remove != -1 and !empty($communityid) and confirm_sesskey()) { $communitymanager->block_community_remove_course($communityid, $USER->id); echo $OUTPUT->header(); @@ -152,8 +152,8 @@ $hubselectorform->set_data($fromformdata); //Retrieve courses by web service $courses = null; -if (optional_param('executesearch', 0, PARAM_INTEGER) and confirm_sesskey()) { - $downloadable = optional_param('downloadable', false, PARAM_INTEGER); +if (optional_param('executesearch', 0, PARAM_INT) and confirm_sesskey()) { + $downloadable = optional_param('downloadable', false, PARAM_INT); $options = new stdClass(); if (!empty($fromformdata['coverage'])) { @@ -178,7 +178,7 @@ if (optional_param('executesearch', 0, PARAM_INTEGER) and confirm_sesskey()) { $options->orderby = $fromformdata['orderby']; //the range of course requested - $options->givememore = optional_param('givememore', 0, PARAM_INTEGER); + $options->givememore = optional_param('givememore', 0, PARAM_INT); //check if the selected hub is from the registered list (in this case we use the private token) $token = 'publichub'; diff --git a/blocks/glossary_random/edit_form.php b/blocks/glossary_random/edit_form.php index 70682bd3e83..6de484cc50a 100644 --- a/blocks/glossary_random/edit_form.php +++ b/blocks/glossary_random/edit_form.php @@ -49,7 +49,7 @@ class block_glossary_random_edit_form extends block_edit_form { $mform->addElement('text', 'config_refresh', get_string('refresh', 'block_glossary_random'), array('size' => 5)); $mform->setDefault('config_refresh', 0); - $mform->setType('config_refresh', PARAM_INTEGER); + $mform->setType('config_refresh', PARAM_INT); // and select quotetypes to put in dropdown box $types = array( diff --git a/blocks/quiz_results/edit_form.php b/blocks/quiz_results/edit_form.php index 1f1db86379b..35231b738cf 100644 --- a/blocks/quiz_results/edit_form.php +++ b/blocks/quiz_results/edit_form.php @@ -54,11 +54,11 @@ class block_quiz_results_edit_form extends block_edit_form { $mform->addElement('text', 'config_showbest', get_string('config_show_best', 'block_quiz_results'), array('size' => 3)); $mform->setDefault('config_showbest', 3); - $mform->setType('config_showbest', PARAM_INTEGER); + $mform->setType('config_showbest', PARAM_INT); $mform->addElement('text', 'config_showworst', get_string('config_show_worst', 'block_quiz_results'), array('size' => 3)); $mform->setDefault('config_showworst', 0); - $mform->setType('config_showworst', PARAM_INTEGER); + $mform->setType('config_showworst', PARAM_INT); $mform->addElement('selectyesno', 'config_usegroups', get_string('config_use_groups', 'block_quiz_results')); diff --git a/blocks/rss_client/edit_form.php b/blocks/rss_client/edit_form.php index aaa36757896..922734a3e24 100644 --- a/blocks/rss_client/edit_form.php +++ b/blocks/rss_client/edit_form.php @@ -40,7 +40,7 @@ class block_rss_client_edit_form extends block_edit_form { $mform->setDefault('config_display_description', 0); $mform->addElement('text', 'config_shownumentries', get_string('shownumentrieslabel', 'block_rss_client'), array('size' => 5)); - $mform->setType('config_shownumentries', PARAM_INTEGER); + $mform->setType('config_shownumentries', PARAM_INT); $mform->addRule('config_shownumentries', null, 'numeric', null, 'client'); if (!empty($CFG->block_rss_client_num_entries)) { $mform->setDefault('config_shownumentries', $CFG->block_rss_client_num_entries); diff --git a/blocks/rss_client/editfeed.php b/blocks/rss_client/editfeed.php index d25e090769d..ce7a09bc2aa 100644 --- a/blocks/rss_client/editfeed.php +++ b/blocks/rss_client/editfeed.php @@ -147,8 +147,8 @@ class feed_edit_form extends moodleform { } $returnurl = optional_param('returnurl', '', PARAM_LOCALURL); -$courseid = optional_param('courseid', 0, PARAM_INTEGER); -$rssid = optional_param('rssid', 0, PARAM_INTEGER); // 0 mean create new. +$courseid = optional_param('courseid', 0, PARAM_INT); +$rssid = optional_param('rssid', 0, PARAM_INT); // 0 mean create new. if ($courseid == SITEID) { $courseid = 0; diff --git a/blocks/rss_client/managefeeds.php b/blocks/rss_client/managefeeds.php index 321aed4d7a1..2e3e3c6978f 100644 --- a/blocks/rss_client/managefeeds.php +++ b/blocks/rss_client/managefeeds.php @@ -29,8 +29,8 @@ require_once($CFG->libdir . '/tablelib.php'); require_login(); $returnurl = optional_param('returnurl', '', PARAM_LOCALURL); -$courseid = optional_param('courseid', 0, PARAM_INTEGER); -$deleterssid = optional_param('deleterssid', 0, PARAM_INTEGER); +$courseid = optional_param('courseid', 0, PARAM_INT); +$deleterssid = optional_param('deleterssid', 0, PARAM_INT); if ($courseid == SITEID) { $courseid = 0; diff --git a/blocks/rss_client/viewfeed.php b/blocks/rss_client/viewfeed.php index 469e621283a..d1235c8fcd3 100644 --- a/blocks/rss_client/viewfeed.php +++ b/blocks/rss_client/viewfeed.php @@ -32,8 +32,8 @@ if (isguestuser()) { } $returnurl = optional_param('returnurl', '', PARAM_LOCALURL); -$courseid = optional_param('courseid', 0, PARAM_INTEGER); -$rssid = required_param('rssid', PARAM_INTEGER); +$courseid = optional_param('courseid', 0, PARAM_INT); +$rssid = required_param('rssid', PARAM_INT); if ($courseid = SITEID) { $courseid = 0; diff --git a/blocks/tag_flickr/edit_form.php b/blocks/tag_flickr/edit_form.php index 51898466f33..4e57f196e17 100644 --- a/blocks/tag_flickr/edit_form.php +++ b/blocks/tag_flickr/edit_form.php @@ -37,7 +37,7 @@ class block_tag_flickr_edit_form extends block_edit_form { $mform->setType('config_title', PARAM_MULTILANG); $mform->addElement('text', 'config_numberofphotos', get_string('numberofphotos', 'block_tag_flickr'), array('size' => 5)); - $mform->setType('config_numberofvideos', PARAM_INTEGER); + $mform->setType('config_numberofvideos', PARAM_INT); $mform->addElement('selectyesno', 'config_includerelatedtags', get_string('includerelatedtags', 'block_tag_flickr')); $mform->setDefault('config_includerelatedtags', 0); diff --git a/blocks/tag_youtube/edit_form.php b/blocks/tag_youtube/edit_form.php index 47b4e581084..5b038a59ddd 100644 --- a/blocks/tag_youtube/edit_form.php +++ b/blocks/tag_youtube/edit_form.php @@ -37,7 +37,7 @@ class block_tag_youtube_edit_form extends block_edit_form { $mform->setType('config_title', PARAM_MULTILANG); $mform->addElement('text', 'config_numberofvideos', get_string('numberofvideos', 'block_tag_youtube'), array('size' => 5)); - $mform->setType('config_numberofvideos', PARAM_INTEGER); + $mform->setType('config_numberofvideos', PARAM_INT); $categorychoices = $this->block->get_categories(); $mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'), $categorychoices); diff --git a/group/externallib.php b/group/externallib.php index 39db0871a1f..4e0ad27533b 100644 --- a/group/externallib.php +++ b/group/externallib.php @@ -311,7 +311,7 @@ class core_group_external extends external_api { foreach ($params['groupids'] as $groupid) { // validate params - $groupid = validate_param($groupid, PARAM_INTEGER); + $groupid = validate_param($groupid, PARAM_INT); if (!$group = groups_get_group($groupid, 'id, courseid', IGNORE_MISSING)) { // silently ignore attempts to delete nonexisting groups continue; diff --git a/lib/blocklib.php b/lib/blocklib.php index 1c7097e9246..6094a2b2668 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -1108,7 +1108,7 @@ class block_manager { * @return boolean true if anything was done. False if not. */ public function process_url_delete() { - $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER); + $blockid = optional_param('bui_deleteid', null, PARAM_INT); if (!$blockid) { return false; } @@ -1134,9 +1134,9 @@ class block_manager { * @return boolean true if anything was done. False if not. */ public function process_url_show_hide() { - if ($blockid = optional_param('bui_hideid', null, PARAM_INTEGER)) { + if ($blockid = optional_param('bui_hideid', null, PARAM_INT)) { $newvisibility = 0; - } else if ($blockid = optional_param('bui_showid', null, PARAM_INTEGER)) { + } else if ($blockid = optional_param('bui_showid', null, PARAM_INT)) { $newvisibility = 1; } else { return false; @@ -1169,7 +1169,7 @@ class block_manager { public function process_url_edit() { global $CFG, $DB, $PAGE, $OUTPUT; - $blockid = optional_param('bui_editid', null, PARAM_INTEGER); + $blockid = optional_param('bui_editid', null, PARAM_INT); if (!$blockid) { return false; } @@ -1367,7 +1367,7 @@ class block_manager { public function process_url_move() { global $CFG, $DB, $PAGE; - $blockid = optional_param('bui_moveid', null, PARAM_INTEGER); + $blockid = optional_param('bui_moveid', null, PARAM_INT); if (!$blockid) { return false; } diff --git a/lib/moodlelib.php b/lib/moodlelib.php index b2c6223bb46..a6bc1fb2711 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -254,6 +254,7 @@ define('PARAM_CLEAN', 'clean'); /** * PARAM_INTEGER - deprecated alias for PARAM_INT + * @deprecated since 2.0 */ define('PARAM_INTEGER', 'int'); diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index bb8c01f1c88..196694c9828 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -26,9 +26,9 @@ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); // Look for old-style URLs, such as may be in the logs, and redirect them to startattemtp.php. -if ($id = optional_param('id', 0, PARAM_INTEGER)) { +if ($id = optional_param('id', 0, PARAM_INT)) { redirect($CFG->wwwroot . '/mod/quiz/startattempt.php?cmid=' . $id . '&sesskey=' . sesskey()); -} else if ($qid = optional_param('q', 0, PARAM_INTEGER)) { +} else if ($qid = optional_param('q', 0, PARAM_INT)) { if (!$cm = get_coursemodule_from_instance('quiz', $qid)) { print_error('invalidquizid', 'quiz'); } diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php index 1f108bf6138..dae095139f3 100644 --- a/mod/quiz/edit.php +++ b/mod/quiz/edit.php @@ -324,7 +324,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) { $questionid = $matches[2]; // Make sure two questions don't overwrite each other. If we get a second // question with the same position, shift the second one along to the next gap. - $value = clean_param($value, PARAM_INTEGER); + $value = clean_param($value, PARAM_INT); while (array_key_exists($value, $questions)) { $value++; } diff --git a/mod/quiz/settings.php b/mod/quiz/settings.php index 7652dfa8385..78efa460bcd 100644 --- a/mod/quiz/settings.php +++ b/mod/quiz/settings.php @@ -183,10 +183,10 @@ $quizsettings->add(new admin_setting_configtext_with_advanced('quiz/subnet', // Enforced delay between attempts. $quizsettings->add(new admin_setting_configtext_with_advanced('quiz/delay1', get_string('delay1st2nd', 'quiz'), get_string('configdelay1st2nd', 'quiz'), - array('value' => 0, 'fix' => true), PARAM_INTEGER)); + array('value' => 0, 'fix' => true), PARAM_INT)); $quizsettings->add(new admin_setting_configtext_with_advanced('quiz/delay2', get_string('delaylater', 'quiz'), get_string('configdelaylater', 'quiz'), - array('value' => 0, 'fix' => true), PARAM_INTEGER)); + array('value' => 0, 'fix' => true), PARAM_INT)); // Browser security. $quizsettings->add(new mod_quiz_admin_setting_browsersecurity('quiz/browsersecurity', diff --git a/question/type/match/question.php b/question/type/match/question.php index ab4b36813de..a031c59c8f0 100644 --- a/question/type/match/question.php +++ b/question/type/match/question.php @@ -176,7 +176,7 @@ class qtype_match_question extends question_graded_automatically_with_countback public function get_expected_data() { $vars = array(); foreach ($this->stemorder as $key => $notused) { - $vars[$this->field($key)] = PARAM_INTEGER; + $vars[$this->field($key)] = PARAM_INT; } return $vars; } diff --git a/question/type/truefalse/question.php b/question/type/truefalse/question.php index b68c8212d07..60f3ba029fe 100644 --- a/question/type/truefalse/question.php +++ b/question/type/truefalse/question.php @@ -41,7 +41,7 @@ class qtype_truefalse_question extends question_graded_automatically { public $falseanswerid; public function get_expected_data() { - return array('answer' => PARAM_INTEGER); + return array('answer' => PARAM_INT); } public function get_correct_response() { diff --git a/user/externallib.php b/user/externallib.php index c1d57bc07e7..633771da7c7 100644 --- a/user/externallib.php +++ b/user/externallib.php @@ -61,7 +61,7 @@ class core_user_external extends external_api { 'lang' => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_DEFAULT, $CFG->lang, NULL_NOT_ALLOWED), 'theme' => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL), 'timezone' => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL), - 'mailformat' => new external_value(PARAM_INTEGER, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), + 'mailformat' => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), 'description' => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL), 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL), 'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL), @@ -286,7 +286,7 @@ class core_user_external extends external_api { 'lang' => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED), 'theme' => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL), 'timezone' => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL), - 'mailformat' => new external_value(PARAM_INTEGER, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), + 'mailformat' => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), 'description' => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL), 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL), 'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL), @@ -471,7 +471,7 @@ class core_user_external extends external_api { 'lang' => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL), 'theme' => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL), 'timezone' => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL), - 'mailformat' => new external_value(PARAM_INTEGER, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), + 'mailformat' => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL), 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL), 'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL), 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL), diff --git a/user/selector/lib.php b/user/selector/lib.php index 005762c61a1..35f40658d77 100644 --- a/user/selector/lib.php +++ b/user/selector/lib.php @@ -149,7 +149,7 @@ abstract class user_selector_base { /** * @return array of user objects. The users that were selected. This is a more sophisticated version - * of optional_param($this->name, array(), PARAM_INTEGER) that validates the + * of optional_param($this->name, array(), PARAM_INT) that validates the * returned list of ids against the rules for this user selector. */ public function get_selected_users() { @@ -368,8 +368,8 @@ abstract class user_selector_base { protected function load_selected_users() { // See if we got anything. if ($this->multiselect) { - $userids = optional_param_array($this->name, array(), PARAM_INTEGER); - } else if ($userid = optional_param($this->name, 0, PARAM_INTEGER)) { + $userids = optional_param_array($this->name, array(), PARAM_INT); + } else if ($userid = optional_param($this->name, 0, PARAM_INT)) { $userids = array($userid); } // If there are no users there is nobody to load From 295c012de7841591bc10b7ec8f3ee9f7a31249de Mon Sep 17 00:00:00 2001 From: Dan Marsden Date: Mon, 16 Jul 2012 14:01:33 +1200 Subject: [PATCH 025/106] MDL-34233 SCORM backup - change to using set_source_sql to preserve order of records in backup. --- .../backup/moodle2/backup_scorm_stepslib.php | 65 ++++++++++++++++--- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/mod/scorm/backup/moodle2/backup_scorm_stepslib.php b/mod/scorm/backup/moodle2/backup_scorm_stepslib.php index 27862e4c204..5a1bf0b75c8 100644 --- a/mod/scorm/backup/moodle2/backup_scorm_stepslib.php +++ b/mod/scorm/backup/moodle2/backup_scorm_stepslib.php @@ -127,25 +127,72 @@ class backup_scorm_activity_structure_step extends backup_activity_structure_ste // Define sources $scorm->set_source_table('scorm', array('id' => backup::VAR_ACTIVITYID)); - $sco->set_source_table('scorm_scoes', array('scorm' => backup::VAR_PARENTID)); + // Use set_source_sql for other calls as set_source_table returns records in reverse order + // and order is important for several SCORM fields - esp scorm_scoes. + $sco->set_source_sql(' + SELECT * + FROM {scorm_scoes} + WHERE scorm = :scorm + ORDER BY id', + array('scorm' => backup::VAR_PARENTID)); - $scodata->set_source_table('scorm_scoes_data', array('scoid' => backup::VAR_PARENTID)); + $scodata->set_source_sql(' + SELECT * + FROM {scorm_scoes_data} + WHERE scoid = :scoid + ORDER BY id', + array('scoid' => backup::VAR_PARENTID)); - $seqrulecond->set_source_table('scorm_seq_ruleconds', array('scoid' => backup::VAR_PARENTID)); + $seqrulecond->set_source_sql(' + SELECT * + FROM {scorm_seq_ruleconds} + WHERE scoid = :scoid + ORDER BY id', + array('scoid' => backup::VAR_PARENTID)); - $seqrulecondsdata->set_source_table('scorm_seq_rulecond', array('ruleconditionsid' => backup::VAR_PARENTID)); + $seqrulecondsdata->set_source_sql(' + SELECT * + FROM {scorm_seq_rulecond} + WHERE ruleconditionsid = :ruleconditionsid + ORDER BY id', + array('ruleconditionsid' => backup::VAR_PARENTID)); - $seqrolluprule->set_source_table('scorm_seq_rolluprule', array('scoid' => backup::VAR_PARENTID)); + $seqrolluprule->set_source_sql(' + SELECT * + FROM {scorm_seq_rolluprule} + WHERE scoid = :scoid + ORDER BY id', + array('scoid' => backup::VAR_PARENTID)); - $seqrolluprulecond->set_source_table('scorm_seq_rolluprulecond', array('rollupruleid' => backup::VAR_PARENTID)); + $seqrolluprulecond->set_source_sql(' + SELECT * + FROM {scorm_seq_rolluprulecond} + WHERE rollupruleid = :rollupruleid + ORDER BY id', + array('rollupruleid' => backup::VAR_PARENTID)); - $seqobjective->set_source_table('scorm_seq_objective', array('scoid' => backup::VAR_PARENTID)); + $seqobjective->set_source_sql(' + SELECT * + FROM {scorm_seq_objective} + WHERE scoid = :scoid + ORDER BY id', + array('scoid' => backup::VAR_PARENTID)); - $seqmapinfo->set_source_table('scorm_seq_mapinfo', array('objectiveid' => backup::VAR_PARENTID)); + $seqmapinfo->set_source_sql(' + SELECT * + FROM {scorm_seq_mapinfo} + WHERE objectiveid = :objectiveid + ORDER BY id', + array('objectiveid' => backup::VAR_PARENTID)); // All the rest of elements only happen if we are including user info if ($userinfo) { - $scotrack->set_source_table('scorm_scoes_track', array('scoid' => backup::VAR_PARENTID)); + $scotrack->set_source_sql(' + SELECT * + FROM {scorm_scoes_track} + WHERE scoid = :scoid + ORDER BY id', + array('scoid' => backup::VAR_PARENTID)); } // Define id annotations From 071e68f93e145aadf69a7c898bb0539a839515b1 Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Fri, 11 May 2012 15:50:09 +0800 Subject: [PATCH 026/106] MDL-32945 libraries: Replaced deprecated PARAM_MULTILANG with PARAM_TEXT --- admin/roles/lib.php | 2 +- admin/tool/uploaduser/user_form.php | 8 ++++---- blocks/blog_tags/edit_form.php | 2 +- blocks/glossary_random/edit_form.php | 2 +- blocks/html/edit_form.php | 2 +- blocks/mentees/edit_form.php | 2 +- blocks/tag_flickr/edit_form.php | 2 +- blocks/tag_youtube/edit_form.php | 2 +- blocks/tags/edit_form.php | 2 +- cohort/edit_form.php | 2 +- course/edit_form.php | 4 ++-- course/request_form.php | 4 ++-- enrol/externallib.php | 2 +- grade/report/grader/ajax_callbacks.php | 2 +- group/autogroup_form.php | 4 ++-- group/group_form.php | 2 +- group/grouping_form.php | 2 +- lib/adminlib.php | 2 +- lib/moodlelib.php | 1 + mod/quiz/addrandomform.php | 2 +- question/category_form.php | 4 ++-- question/format.php | 4 ++-- user/editlib.php | 10 +++++----- user/externallib.php | 4 ++-- user/profile/definelib.php | 2 +- user/profile/field/menu/define.class.php | 4 ++-- user/profile/field/text/define.class.php | 2 +- user/profile/field/text/field.class.php | 2 +- user/profile/index_category_form.php | 2 +- 29 files changed, 43 insertions(+), 42 deletions(-) diff --git a/admin/roles/lib.php b/admin/roles/lib.php index 212cd211c6f..490e0a133c8 100644 --- a/admin/roles/lib.php +++ b/admin/roles/lib.php @@ -604,7 +604,7 @@ class define_role_table_advanced extends capability_table_with_risks { } // Role name. - $name = optional_param('name', null, PARAM_MULTILANG); + $name = optional_param('name', null, PARAM_TEXT); if (!is_null($name)) { $this->role->name = $name; // Hack: short names of standard roles are equal to archetypes, empty name means localised via lang packs. diff --git a/admin/tool/uploaduser/user_form.php b/admin/tool/uploaduser/user_form.php index 7e7d790fd97..08d2c0e8a1f 100644 --- a/admin/tool/uploaduser/user_form.php +++ b/admin/tool/uploaduser/user_form.php @@ -249,7 +249,7 @@ class admin_uploaduser_form2 extends moodleform { } $mform->addElement('text', 'city', get_string('city'), 'maxlength="100" size="25"'); - $mform->setType('city', PARAM_MULTILANG); + $mform->setType('city', PARAM_TEXT); if (empty($CFG->defaultcity)) { $mform->setDefault('city', $templateuser->city); } else { @@ -288,11 +288,11 @@ class admin_uploaduser_form2 extends moodleform { $mform->setType('idnumber', PARAM_NOTAGS); $mform->addElement('text', 'institution', get_string('institution'), 'maxlength="40" size="25"'); - $mform->setType('institution', PARAM_MULTILANG); + $mform->setType('institution', PARAM_TEXT); $mform->setDefault('institution', $templateuser->institution); $mform->addElement('text', 'department', get_string('department'), 'maxlength="30" size="25"'); - $mform->setType('department', PARAM_MULTILANG); + $mform->setType('department', PARAM_TEXT); $mform->setDefault('department', $templateuser->department); $mform->addElement('text', 'phone1', get_string('phone'), 'maxlength="20" size="25"'); @@ -304,7 +304,7 @@ class admin_uploaduser_form2 extends moodleform { $mform->setAdvanced('phone2'); $mform->addElement('text', 'address', get_string('address'), 'maxlength="70" size="25"'); - $mform->setType('address', PARAM_MULTILANG); + $mform->setType('address', PARAM_TEXT); $mform->setAdvanced('address'); // Next the profile defaults diff --git a/blocks/blog_tags/edit_form.php b/blocks/blog_tags/edit_form.php index 1571066013c..8d59fa97326 100644 --- a/blocks/blog_tags/edit_form.php +++ b/blocks/blog_tags/edit_form.php @@ -36,7 +36,7 @@ class block_blog_tags_edit_form extends block_edit_form { $mform->addElement('text', 'config_title', get_string('blocktitle', 'blog')); $mform->setDefault('config_title', get_string('blogtags', 'blog')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); $numberoftags = array(); for($i = 1; $i <= 50; $i++) { diff --git a/blocks/glossary_random/edit_form.php b/blocks/glossary_random/edit_form.php index 70682bd3e83..d745aa3329c 100644 --- a/blocks/glossary_random/edit_form.php +++ b/blocks/glossary_random/edit_form.php @@ -38,7 +38,7 @@ class block_glossary_random_edit_form extends block_edit_form { $mform->addElement('text', 'config_title', get_string('title', 'block_glossary_random')); $mform->setDefault('config_title', get_string('pluginname','block_glossary_random')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); // Select glossaries to put in dropdown box ... $glossaries = $DB->get_records_menu('glossary', array('course' => $this->block->course->id), 'name', 'id,name'); diff --git a/blocks/html/edit_form.php b/blocks/html/edit_form.php index aa7b4661de8..b7251905e58 100644 --- a/blocks/html/edit_form.php +++ b/blocks/html/edit_form.php @@ -35,7 +35,7 @@ class block_html_edit_form extends block_edit_form { $mform->addElement('header', 'configheader', get_string('blocksettings', 'block')); $mform->addElement('text', 'config_title', get_string('configtitle', 'block_html')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); $editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'noclean'=>true, 'context'=>$this->block->context); $mform->addElement('editor', 'config_text', get_string('configcontent', 'block_html'), null, $editoroptions); diff --git a/blocks/mentees/edit_form.php b/blocks/mentees/edit_form.php index 760d5fdbe0b..5b3430d7939 100644 --- a/blocks/mentees/edit_form.php +++ b/blocks/mentees/edit_form.php @@ -35,6 +35,6 @@ class block_mentees_edit_form extends block_edit_form { $mform->addElement('header', 'configheader', get_string('blocksettings', 'block')); $mform->addElement('text', 'config_title', get_string('configtitleblankhides', 'block_mentees')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); } } \ No newline at end of file diff --git a/blocks/tag_flickr/edit_form.php b/blocks/tag_flickr/edit_form.php index 51898466f33..309f7482cfa 100644 --- a/blocks/tag_flickr/edit_form.php +++ b/blocks/tag_flickr/edit_form.php @@ -34,7 +34,7 @@ class block_tag_flickr_edit_form extends block_edit_form { $mform->addElement('header', 'configheader', get_string('blocksettings', 'block')); $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tag_flickr')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); $mform->addElement('text', 'config_numberofphotos', get_string('numberofphotos', 'block_tag_flickr'), array('size' => 5)); $mform->setType('config_numberofvideos', PARAM_INTEGER); diff --git a/blocks/tag_youtube/edit_form.php b/blocks/tag_youtube/edit_form.php index 47b4e581084..6275ff96f23 100644 --- a/blocks/tag_youtube/edit_form.php +++ b/blocks/tag_youtube/edit_form.php @@ -34,7 +34,7 @@ class block_tag_youtube_edit_form extends block_edit_form { $mform->addElement('header', 'configheader', get_string('blocksettings', 'block')); $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tag_youtube')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); $mform->addElement('text', 'config_numberofvideos', get_string('numberofvideos', 'block_tag_youtube'), array('size' => 5)); $mform->setType('config_numberofvideos', PARAM_INTEGER); diff --git a/blocks/tags/edit_form.php b/blocks/tags/edit_form.php index eec32025a9b..ea7f3cb9cb3 100644 --- a/blocks/tags/edit_form.php +++ b/blocks/tags/edit_form.php @@ -35,7 +35,7 @@ class block_tags_edit_form extends block_edit_form { $mform->addElement('header', 'configheader', get_string('blocksettings', 'block')); $mform->addElement('text', 'config_title', get_string('pluginname', 'block_tags')); - $mform->setType('config_title', PARAM_MULTILANG); + $mform->setType('config_title', PARAM_TEXT); $mform->setDefault('config_title', get_string('pluginname', 'block_tags')); $numberoftags = array(); diff --git a/cohort/edit_form.php b/cohort/edit_form.php index d449980f87e..a030ce20232 100644 --- a/cohort/edit_form.php +++ b/cohort/edit_form.php @@ -43,7 +43,7 @@ class cohort_edit_form extends moodleform { $mform->addElement('text', 'name', get_string('name', 'cohort'), 'maxlength="254" size="50"'); $mform->addRule('name', get_string('required'), 'required', null, 'client'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $options = $this->get_category_options($cohort->contextid); $mform->addElement('select', 'contextid', get_string('context', 'role'), $options); diff --git a/course/edit_form.php b/course/edit_form.php index 1b7584981b5..e665c039c4e 100644 --- a/course/edit_form.php +++ b/course/edit_form.php @@ -79,7 +79,7 @@ class course_edit_form extends moodleform { $mform->addElement('text','fullname', get_string('fullnamecourse'),'maxlength="254" size="50"'); $mform->addHelpButton('fullname', 'fullnamecourse'); $mform->addRule('fullname', get_string('missingfullname'), 'required', null, 'client'); - $mform->setType('fullname', PARAM_MULTILANG); + $mform->setType('fullname', PARAM_TEXT); if (!empty($course->id) and !has_capability('moodle/course:changefullname', $coursecontext)) { $mform->hardFreeze('fullname'); $mform->setConstant('fullname', $course->fullname); @@ -88,7 +88,7 @@ class course_edit_form extends moodleform { $mform->addElement('text', 'shortname', get_string('shortnamecourse'), 'maxlength="100" size="20"'); $mform->addHelpButton('shortname', 'shortnamecourse'); $mform->addRule('shortname', get_string('missingshortname'), 'required', null, 'client'); - $mform->setType('shortname', PARAM_MULTILANG); + $mform->setType('shortname', PARAM_TEXT); if (!empty($course->id) and !has_capability('moodle/course:changeshortname', $coursecontext)) { $mform->hardFreeze('shortname'); $mform->setConstant('shortname', $course->shortname); diff --git a/course/request_form.php b/course/request_form.php index 80e60f0be8e..e74e40bdf71 100644 --- a/course/request_form.php +++ b/course/request_form.php @@ -61,12 +61,12 @@ class course_request_form extends moodleform { $mform->addElement('text', 'fullname', get_string('fullnamecourse'), 'maxlength="254" size="50"'); $mform->addHelpButton('fullname', 'fullnamecourse'); $mform->addRule('fullname', get_string('missingfullname'), 'required', null, 'client'); - $mform->setType('fullname', PARAM_MULTILANG); + $mform->setType('fullname', PARAM_TEXT); $mform->addElement('text', 'shortname', get_string('shortnamecourse'), 'maxlength="100" size="20"'); $mform->addHelpButton('shortname', 'shortnamecourse'); $mform->addRule('shortname', get_string('missingshortname'), 'required', null, 'client'); - $mform->setType('shortname', PARAM_MULTILANG); + $mform->setType('shortname', PARAM_TEXT); $mform->addElement('editor', 'summary_editor', get_string('summary'), null, course_request::summary_editor_options()); $mform->addHelpButton('summary_editor', 'coursesummary'); diff --git a/enrol/externallib.php b/enrol/externallib.php index 147383c9808..1b842cca39c 100644 --- a/enrol/externallib.php +++ b/enrol/externallib.php @@ -263,7 +263,7 @@ class core_enrol_external extends external_api { 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL), 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'), 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL), - 'address' => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL), + 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL), 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL), 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL), 'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL), diff --git a/grade/report/grader/ajax_callbacks.php b/grade/report/grader/ajax_callbacks.php index 034ef18c2dc..1630f850b23 100644 --- a/grade/report/grader/ajax_callbacks.php +++ b/grade/report/grader/ajax_callbacks.php @@ -33,7 +33,7 @@ $userid = optional_param('userid', false, PARAM_INT); $itemid = optional_param('itemid', false, PARAM_INT); $type = optional_param('type', false, PARAM_ALPHA); $action = optional_param('action', false, PARAM_ALPHA); -$newvalue = optional_param('newvalue', false, PARAM_MULTILANG); +$newvalue = optional_param('newvalue', false, PARAM_TEXT); /// basic access checks if (!$course = $DB->get_record('course', array('id' => $courseid))) { diff --git a/group/autogroup_form.php b/group/autogroup_form.php index 5b39965de68..36343b52573 100644 --- a/group/autogroup_form.php +++ b/group/autogroup_form.php @@ -102,7 +102,7 @@ class autogroup_form extends moodleform { $mform->addElement('text', 'namingscheme', get_string('namingscheme', 'group')); $mform->addHelpButton('namingscheme', 'namingscheme', 'group'); $mform->addRule('namingscheme', get_string('required'), 'required', null, 'client'); - $mform->setType('namingscheme', PARAM_MULTILANG); + $mform->setType('namingscheme', PARAM_TEXT); // there must not be duplicate group names in course $template = get_string('grouptemplate', 'group'); $gname = groups_parse_name($template, 0); @@ -123,7 +123,7 @@ class autogroup_form extends moodleform { } $mform->addElement('text', 'groupingname', get_string('groupingname', 'group'), $options); - $mform->setType('groupingname', PARAM_MULTILANG); + $mform->setType('groupingname', PARAM_TEXT); $mform->disabledIf('groupingname', 'grouping', 'noteq', '-1'); $mform->addElement('hidden','courseid'); diff --git a/group/group_form.php b/group/group_form.php index 18fe0990b25..98f2c9dda13 100644 --- a/group/group_form.php +++ b/group/group_form.php @@ -50,7 +50,7 @@ class group_form extends moodleform { $mform->addElement('text','name', get_string('groupname', 'group'),'maxlength="254" size="50"'); $mform->addRule('name', get_string('required'), 'required', null, 'client'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $mform->addElement('text','idnumber', get_string('idnumbergroup'), 'maxlength="100" size="10"'); $mform->addHelpButton('idnumber', 'idnumbergroup'); diff --git a/group/grouping_form.php b/group/grouping_form.php index 63248ab1805..1f15bc78b5f 100644 --- a/group/grouping_form.php +++ b/group/grouping_form.php @@ -52,7 +52,7 @@ class grouping_form extends moodleform { $mform->addElement('text','name', get_string('groupingname', 'group'),'maxlength="254" size="50"'); $mform->addRule('name', get_string('required'), 'required', null, 'server'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $mform->addElement('text','idnumber', get_string('idnumbergrouping'), 'maxlength="100" size="10"'); $mform->addHelpButton('idnumber', 'idnumbergrouping'); diff --git a/lib/adminlib.php b/lib/adminlib.php index 0626e662581..ece35ca87c3 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -3243,7 +3243,7 @@ class admin_setting_sitesettext extends admin_setting_configtext { * @return mixed true or message string */ public function validate($data) { - $cleaned = clean_param($data, PARAM_MULTILANG); + $cleaned = clean_param($data, PARAM_TEXT); if ($cleaned === '') { return get_string('required'); } diff --git a/lib/moodlelib.php b/lib/moodlelib.php index b2c6223bb46..ebb9d111eff 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -276,6 +276,7 @@ define('PARAM_FORMAT', 'alphanumext'); /** * PARAM_MULTILANG - deprecated alias of PARAM_TEXT. + * @deprecated since 2.0 */ define('PARAM_MULTILANG', 'text'); diff --git a/mod/quiz/addrandomform.php b/mod/quiz/addrandomform.php index 3b37a1d4de3..fa8a2e947eb 100644 --- a/mod/quiz/addrandomform.php +++ b/mod/quiz/addrandomform.php @@ -60,7 +60,7 @@ class quiz_add_random_form extends moodleform { get_string('randomquestionusinganewcategory', 'quiz')); $mform->addElement('text', 'name', get_string('name'), 'maxlength="254" size="50"'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'), array('contexts' => $usablecontexts, 'top' => true)); diff --git a/question/category_form.php b/question/category_form.php index 357b1a4f8be..600ee888625 100644 --- a/question/category_form.php +++ b/question/category_form.php @@ -57,11 +57,11 @@ class question_category_edit_form extends moodleform { $mform->addElement('text', 'name', get_string('name'),'maxlength="254" size="50"'); $mform->setDefault('name', ''); $mform->addRule('name', get_string('categorynamecantbeblank', 'question'), 'required', null, 'client'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $mform->addElement('textarea', 'info', get_string('categoryinfo', 'question'), array('rows'=> '10', 'cols'=>'45')); $mform->setDefault('info', ''); - $mform->setType('info', PARAM_MULTILANG); + $mform->setType('info', PARAM_TEXT); $this->add_action_buttons(false, get_string('addcategory', 'question')); diff --git a/question/format.php b/question/format.php index 0ccdbce99e9..9b0bf37b99c 100644 --- a/question/format.php +++ b/question/format.php @@ -849,7 +849,7 @@ class qformat_default { * Convert a string, as returned by {@link assemble_category_path()}, * back into an array of category names. * - * Each category name is cleaned by a call to clean_param(, PARAM_MULTILANG), + * Each category name is cleaned by a call to clean_param(, PARAM_TEXT), * which matches the cleaning in question/category_form.php. * * @param string $path @@ -859,7 +859,7 @@ class qformat_default { $rawnames = preg_split('~(?addHelpButton('screenreader', 'screenreaderuse'); $mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="21"'); - $mform->setType('city', PARAM_MULTILANG); + $mform->setType('city', PARAM_TEXT); $mform->addRule('city', $strrequired, 'required', null, 'client'); if (!empty($CFG->defaultcity)) { $mform->setDefault('city', $CFG->defaultcity); @@ -282,7 +282,7 @@ function useredit_shared_definition(&$mform, $editoroptions = null, $filemanager $mform->addHelpButton('imagefile', 'newpicture'); $mform->addElement('text', 'imagealt', get_string('imagealt'), 'maxlength="100" size="30"'); - $mform->setType('imagealt', PARAM_MULTILANG); + $mform->setType('imagealt', PARAM_TEXT); } @@ -317,10 +317,10 @@ function useredit_shared_definition(&$mform, $editoroptions = null, $filemanager $mform->setType('idnumber', PARAM_NOTAGS); $mform->addElement('text', 'institution', get_string('institution'), 'maxlength="40" size="25"'); - $mform->setType('institution', PARAM_MULTILANG); + $mform->setType('institution', PARAM_TEXT); $mform->addElement('text', 'department', get_string('department'), 'maxlength="30" size="25"'); - $mform->setType('department', PARAM_MULTILANG); + $mform->setType('department', PARAM_TEXT); $mform->addElement('text', 'phone1', get_string('phone'), 'maxlength="20" size="25"'); $mform->setType('phone1', PARAM_NOTAGS); @@ -329,7 +329,7 @@ function useredit_shared_definition(&$mform, $editoroptions = null, $filemanager $mform->setType('phone2', PARAM_NOTAGS); $mform->addElement('text', 'address', get_string('address'), 'maxlength="70" size="25"'); - $mform->setType('address', PARAM_MULTILANG); + $mform->setType('address', PARAM_TEXT); } diff --git a/user/externallib.php b/user/externallib.php index c1d57bc07e7..417c8b1e665 100644 --- a/user/externallib.php +++ b/user/externallib.php @@ -452,7 +452,7 @@ class core_user_external extends external_api { 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL), 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'), 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL), - 'address' => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL), + 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL), 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL), 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL), 'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL), @@ -604,7 +604,7 @@ class core_user_external extends external_api { 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL), 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'), 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL), - 'address' => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL), + 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL), 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL), 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL), 'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL), diff --git a/user/profile/definelib.php b/user/profile/definelib.php index 50ecbd964a9..c73baf32486 100644 --- a/user/profile/definelib.php +++ b/user/profile/definelib.php @@ -29,7 +29,7 @@ class profile_define_base { $form->addElement('text', 'name', get_string('profilename', 'admin'), 'size="50"'); $form->addRule('name', $strrequired, 'required', null, 'client'); - $form->setType('name', PARAM_MULTILANG); + $form->setType('name', PARAM_TEXT); $form->addElement('editor', 'description', get_string('profiledescription', 'admin'), null, null); diff --git a/user/profile/field/menu/define.class.php b/user/profile/field/menu/define.class.php index e26d0f771b2..fb29323502f 100644 --- a/user/profile/field/menu/define.class.php +++ b/user/profile/field/menu/define.class.php @@ -5,11 +5,11 @@ class profile_define_menu extends profile_define_base { function define_form_specific($form) { /// Param 1 for menu type contains the options $form->addElement('textarea', 'param1', get_string('profilemenuoptions', 'admin'), array('rows' => 6, 'cols' => 40)); - $form->setType('param1', PARAM_MULTILANG); + $form->setType('param1', PARAM_TEXT); /// Default data $form->addElement('text', 'defaultdata', get_string('profiledefaultdata', 'admin'), 'size="50"'); - $form->setType('defaultdata', PARAM_MULTILANG); + $form->setType('defaultdata', PARAM_TEXT); } function define_validate_specific($data, $files) { diff --git a/user/profile/field/text/define.class.php b/user/profile/field/text/define.class.php index fe7731c034c..191b758545e 100644 --- a/user/profile/field/text/define.class.php +++ b/user/profile/field/text/define.class.php @@ -5,7 +5,7 @@ class profile_define_text extends profile_define_base { function define_form_specific($form) { /// Default data $form->addElement('text', 'defaultdata', get_string('profiledefaultdata', 'admin'), 'size="50"'); - $form->setType('defaultdata', PARAM_MULTILANG); + $form->setType('defaultdata', PARAM_TEXT); /// Param 1 for text type is the size of the field $form->addElement('text', 'param1', get_string('profilefieldsize', 'admin'), 'size="6"'); diff --git a/user/profile/field/text/field.class.php b/user/profile/field/text/field.class.php index de726ae5030..9c4b43307b1 100644 --- a/user/profile/field/text/field.class.php +++ b/user/profile/field/text/field.class.php @@ -33,7 +33,7 @@ class profile_field_text extends profile_field_base { /// Create the form field $mform->addElement($fieldtype, $this->inputname, format_string($this->field->name), 'maxlength="'.$maxlength.'" size="'.$size.'" '); - $mform->setType($this->inputname, PARAM_MULTILANG); + $mform->setType($this->inputname, PARAM_TEXT); } } diff --git a/user/profile/index_category_form.php b/user/profile/index_category_form.php index ee8acc48770..1ee3bf80f5e 100644 --- a/user/profile/index_category_form.php +++ b/user/profile/index_category_form.php @@ -23,7 +23,7 @@ class category_form extends moodleform { $mform->setType('action', PARAM_ACTION); $mform->addElement('text', 'name', get_string('profilecategoryname', 'admin'), 'maxlength="255" size="30"'); - $mform->setType('name', PARAM_MULTILANG); + $mform->setType('name', PARAM_TEXT); $mform->addRule('name', $strrequired, 'required', null, 'client'); $this->add_action_buttons(true); From 405aca353253c2c727ed9343bdb19b6aff5884c1 Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Fri, 11 May 2012 13:42:27 +0800 Subject: [PATCH 027/106] MDL-32942 libraries: Replaced deprecated PARAM_ACTION and PARAM_FORMAT with PARAM_ALPHANUMEXT --- admin/auth.php | 2 +- admin/editors.php | 2 +- admin/enrol.php | 2 +- admin/environment.php | 2 +- admin/filters.php | 2 +- admin/licenses.php | 2 +- admin/portfolio.php | 2 +- admin/repository.php | 2 +- admin/roles/allow.php | 2 +- admin/tool/unsuproles/index.php | 2 +- admin/webservice/forms.php | 4 ++-- admin/webservice/protocols.php | 2 +- admin/webservice/service.php | 2 +- admin/webservice/service_functions.php | 2 +- admin/webservice/tokens.php | 2 +- blog/edit_form.php | 2 +- enrol/ajax.php | 2 +- enrol/bulkchange.php | 2 +- enrol/cohort/ajax.php | 2 +- enrol/instances.php | 2 +- enrol/manual/ajax.php | 2 +- enrol/otherusers.php | 2 +- enrol/users.php | 2 +- enrol/users_forms.php | 4 ++-- grade/edit/outcome/import_outcomes_form.php | 2 +- lib/moodlelib.php | 2 ++ lib/tests/performance/filtersettingsperformancetester.php | 2 +- mod/glossary/formats.php | 2 +- mod/lti/typessettings.php | 2 +- mod/wiki/editcomments.php | 2 +- mod/wiki/instancecomments.php | 2 +- question/type/essay/question.php | 2 +- repository/lib.php | 2 +- repository/manage_instances.php | 2 +- user/managetoken.php | 4 ++-- user/profile/index_category_form.php | 2 +- user/profile/index_field_form.php | 2 +- 37 files changed, 41 insertions(+), 39 deletions(-) diff --git a/admin/auth.php b/admin/auth.php index 93711ee8324..c5ebb80b758 100644 --- a/admin/auth.php +++ b/admin/auth.php @@ -18,7 +18,7 @@ $returnurl = new moodle_url('/admin/settings.php', array('section'=>'manageauths $PAGE->set_url($returnurl); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $auth = optional_param('auth', '', PARAM_PLUGIN); get_enabled_auth_plugins(true); // fix the list of enabled auths diff --git a/admin/editors.php b/admin/editors.php index fbb7be5aac4..743d083e43b 100644 --- a/admin/editors.php +++ b/admin/editors.php @@ -13,7 +13,7 @@ require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); $returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageeditors"; -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $editor = optional_param('editor', '', PARAM_PLUGIN); // get currently installed and enabled auth plugins diff --git a/admin/enrol.php b/admin/enrol.php index ab14a23440a..dee82d3c559 100644 --- a/admin/enrol.php +++ b/admin/enrol.php @@ -26,7 +26,7 @@ require_once('../config.php'); require_once($CFG->libdir.'/adminlib.php'); -$action = required_param('action', PARAM_ACTION); +$action = required_param('action', PARAM_ALPHANUMEXT); $enrol = required_param('enrol', PARAM_PLUGIN); $confirm = optional_param('confirm', 0, PARAM_BOOL); diff --git a/admin/environment.php b/admin/environment.php index 1fc732ea064..5c74f7f6365 100644 --- a/admin/environment.php +++ b/admin/environment.php @@ -33,7 +33,7 @@ require_once($CFG->libdir.'/environmentlib.php'); require_once($CFG->libdir.'/componentlib.class.php'); // Parameters -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $version = optional_param('version', '', PARAM_FILE); // $extraurlparams = array(); diff --git a/admin/filters.php b/admin/filters.php index 0d7faa3c088..5c3a19165dd 100644 --- a/admin/filters.php +++ b/admin/filters.php @@ -34,7 +34,7 @@ require_once(dirname(__FILE__) . '/../config.php'); require_once($CFG->libdir . '/adminlib.php'); - $action = optional_param('action', '', PARAM_ACTION); + $action = optional_param('action', '', PARAM_ALPHANUMEXT); $filterpath = optional_param('filterpath', '', PARAM_PATH); require_login(); diff --git a/admin/licenses.php b/admin/licenses.php index dfd843d009d..517ba85291d 100644 --- a/admin/licenses.php +++ b/admin/licenses.php @@ -28,7 +28,7 @@ require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); $returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=managelicenses"; -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $license = optional_param('license', '', PARAM_SAFEDIR); //////////////////////////////////////////////////////////////////////////////// diff --git a/admin/portfolio.php b/admin/portfolio.php index 791c79f9489..09a769577c3 100644 --- a/admin/portfolio.php +++ b/admin/portfolio.php @@ -5,7 +5,7 @@ require_once($CFG->libdir . '/portfoliolib.php'); require_once($CFG->libdir . '/portfolio/forms.php'); require_once($CFG->libdir . '/adminlib.php'); -$portfolio = optional_param('pf', '', PARAM_FORMAT); +$portfolio = optional_param('pf', '', PARAM_ALPHANUMEXT); $action = optional_param('action', '', PARAM_ALPHA); $sure = optional_param('sure', '', PARAM_ALPHA); diff --git a/admin/repository.php b/admin/repository.php index b3494cab5a5..377a006fc67 100644 --- a/admin/repository.php +++ b/admin/repository.php @@ -19,7 +19,7 @@ require_once($CFG->dirroot . '/repository/lib.php'); require_once($CFG->libdir . '/adminlib.php'); $repository = optional_param('repos', '', PARAM_ALPHANUMEXT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $sure = optional_param('sure', '', PARAM_ALPHA); $downloadcontents = optional_param('downloadcontents', false, PARAM_BOOL); diff --git a/admin/roles/allow.php b/admin/roles/allow.php index 52078e7f181..45e9b038673 100644 --- a/admin/roles/allow.php +++ b/admin/roles/allow.php @@ -28,7 +28,7 @@ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->libdir . '/adminlib.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/roles/lib.php'); -$mode = required_param('mode', PARAM_ACTION); +$mode = required_param('mode', PARAM_ALPHANUMEXT); $classformode = array( 'assign' => 'role_allow_assign_page', 'override' => 'role_allow_override_page', diff --git a/admin/tool/unsuproles/index.php b/admin/tool/unsuproles/index.php index 0018ec1bdd7..144df3420e8 100644 --- a/admin/tool/unsuproles/index.php +++ b/admin/tool/unsuproles/index.php @@ -27,7 +27,7 @@ require_once(dirname(__FILE__) . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $syscontext = get_context_instance(CONTEXT_SYSTEM); diff --git a/admin/webservice/forms.php b/admin/webservice/forms.php index 13e1c3ddc4f..fef6a753fe8 100644 --- a/admin/webservice/forms.php +++ b/admin/webservice/forms.php @@ -168,7 +168,7 @@ class external_service_functions_form extends moodleform { $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $this->add_action_buttons(true, get_string('addfunctions', 'webservice')); @@ -236,7 +236,7 @@ class web_service_token_form extends moodleform { get_string('validuntil', 'webservice'), array('optional' => true)); $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $this->add_action_buttons(true); diff --git a/admin/webservice/protocols.php b/admin/webservice/protocols.php index 6448a96a996..9e7fcfb1548 100644 --- a/admin/webservice/protocols.php +++ b/admin/webservice/protocols.php @@ -35,7 +35,7 @@ require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); $returnurl = $CFG->wwwroot . "/" . $CFG->admin . "/settings.php?section=webserviceprotocols"; -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $webservice = optional_param('webservice', '', PARAM_SAFEDIR); $confirm = optional_param('confirm', 0, PARAM_BOOL); diff --git a/admin/webservice/service.php b/admin/webservice/service.php index f8761d35f81..a933ec4af41 100644 --- a/admin/webservice/service.php +++ b/admin/webservice/service.php @@ -40,7 +40,7 @@ $PAGE->navbar->add(get_string('externalservice', 'webservice')); //Retrieve few general parameters $id = required_param('id', PARAM_INT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $confirm = optional_param('confirm', 0, PARAM_BOOL); $webservicemanager = new webservice; $renderer = $PAGE->get_renderer('core', 'webservice'); diff --git a/admin/webservice/service_functions.php b/admin/webservice/service_functions.php index 1b2fd225333..3df598487d8 100644 --- a/admin/webservice/service_functions.php +++ b/admin/webservice/service_functions.php @@ -30,7 +30,7 @@ require_once('forms.php'); $serviceid = required_param('id', PARAM_INT); $functionid = optional_param('fid', 0, PARAM_INT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $confirm = optional_param('confirm', 0, PARAM_BOOL); admin_externalpage_setup('externalservicefunctions'); diff --git a/admin/webservice/tokens.php b/admin/webservice/tokens.php index cf229ab5446..7e1766325b6 100644 --- a/admin/webservice/tokens.php +++ b/admin/webservice/tokens.php @@ -28,7 +28,7 @@ require_once($CFG->libdir . '/adminlib.php'); require_once($CFG->dirroot . '/' . $CFG->admin . '/webservice/forms.php'); require_once($CFG->libdir . '/externallib.php'); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $tokenid = optional_param('tokenid', '', PARAM_SAFEDIR); $confirm = optional_param('confirm', 0, PARAM_BOOL); diff --git a/blog/edit_form.php b/blog/edit_form.php index 292d55cf7af..bd10367b733 100644 --- a/blog/edit_form.php +++ b/blog/edit_form.php @@ -111,7 +111,7 @@ class blog_edit_form extends moodleform { $this->add_action_buttons(); $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->setDefault('action', ''); $mform->addElement('hidden', 'entryid'); diff --git a/enrol/ajax.php b/enrol/ajax.php index 8a0bdfc09a7..3e855188546 100644 --- a/enrol/ajax.php +++ b/enrol/ajax.php @@ -35,7 +35,7 @@ require_once("$CFG->dirroot/group/lib.php"); // Must have the sesskey $id = required_param('id', PARAM_INT); // course id -$action = required_param('action', PARAM_ACTION); +$action = required_param('action', PARAM_ALPHANUMEXT); $PAGE->set_url(new moodle_url('/enrol/ajax.php', array('id'=>$id, 'action'=>$action))); diff --git a/enrol/bulkchange.php b/enrol/bulkchange.php index d033a56ed67..827b9fd1922 100644 --- a/enrol/bulkchange.php +++ b/enrol/bulkchange.php @@ -32,7 +32,7 @@ require_once("$CFG->dirroot/group/lib.php"); $id = required_param('id', PARAM_INT); // course id $bulkuserop = required_param('bulkuserop', PARAM_ALPHANUMEXT); $userids = required_param_array('bulkuser', PARAM_INT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $filter = optional_param('ifilter', 0, PARAM_INT); $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); diff --git a/enrol/cohort/ajax.php b/enrol/cohort/ajax.php index e65d1ed8456..91d4131e260 100644 --- a/enrol/cohort/ajax.php +++ b/enrol/cohort/ajax.php @@ -35,7 +35,7 @@ require_once($CFG->dirroot.'/group/lib.php'); // Must have the sesskey $id = required_param('id', PARAM_INT); // course id -$action = required_param('action', PARAM_ACTION); +$action = required_param('action', PARAM_ALPHANUMEXT); $PAGE->set_url(new moodle_url('/enrol/cohort/ajax.php', array('id'=>$id, 'action'=>$action))); diff --git a/enrol/instances.php b/enrol/instances.php index 3f8b2dbccdd..3007273a7cb 100644 --- a/enrol/instances.php +++ b/enrol/instances.php @@ -26,7 +26,7 @@ require('../config.php'); $id = required_param('id', PARAM_INT); // course id -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $instanceid = optional_param('instance', 0, PARAM_INT); $confirm = optional_param('confirm', 0, PARAM_BOOL); diff --git a/enrol/manual/ajax.php b/enrol/manual/ajax.php index a9d5bb7f804..b480a0e2890 100644 --- a/enrol/manual/ajax.php +++ b/enrol/manual/ajax.php @@ -34,7 +34,7 @@ require_once($CFG->dirroot.'/group/lib.php'); // Must have the sesskey $id = required_param('id', PARAM_INT); // course id -$action = required_param('action', PARAM_ACTION); +$action = required_param('action', PARAM_ALPHANUMEXT); $PAGE->set_url(new moodle_url('/enrol/ajax.php', array('id'=>$id, 'action'=>$action))); diff --git a/enrol/otherusers.php b/enrol/otherusers.php index 52b34bfe829..9a70689eb70 100644 --- a/enrol/otherusers.php +++ b/enrol/otherusers.php @@ -29,7 +29,7 @@ require_once("$CFG->dirroot/enrol/renderer.php"); require_once("$CFG->dirroot/group/lib.php"); $id = required_param('id', PARAM_INT); // course id -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $filter = optional_param('ifilter', 0, PARAM_INT); $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); diff --git a/enrol/users.php b/enrol/users.php index 2ebbab5ec8b..eb6beedbfc3 100644 --- a/enrol/users.php +++ b/enrol/users.php @@ -30,7 +30,7 @@ require_once("$CFG->dirroot/enrol/renderer.php"); require_once("$CFG->dirroot/group/lib.php"); $id = required_param('id', PARAM_INT); // course id -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $filter = optional_param('ifilter', 0, PARAM_INT); $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); diff --git a/enrol/users_forms.php b/enrol/users_forms.php index 7263688fdde..63599508caa 100644 --- a/enrol/users_forms.php +++ b/enrol/users_forms.php @@ -56,7 +56,7 @@ class enrol_users_assign_form extends moodleform { $mform->setType('user', PARAM_INT); $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->addElement('hidden', 'ifilter'); $mform->setType('ifilter', PARAM_ALPHA); @@ -110,7 +110,7 @@ class enrol_users_addmember_form extends moodleform { $mform->setType('user', PARAM_INT); $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->addElement('hidden', 'ifilter'); $mform->setType('ifilter', PARAM_ALPHA); diff --git a/grade/edit/outcome/import_outcomes_form.php b/grade/edit/outcome/import_outcomes_form.php index 4a263c8693e..e7e4a1ea1d6 100644 --- a/grade/edit/outcome/import_outcomes_form.php +++ b/grade/edit/outcome/import_outcomes_form.php @@ -36,7 +36,7 @@ class import_outcomes_form extends moodleform { $mform =& $this->_form; $mform->addElement('hidden', 'action', 'upload'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->addElement('hidden', 'courseid', $PAGE->course->id); $mform->setType('id', PARAM_INT); diff --git a/lib/moodlelib.php b/lib/moodlelib.php index b2c6223bb46..dcbef78db72 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -265,12 +265,14 @@ define('PARAM_NUMBER', 'float'); /** * PARAM_ACTION - deprecated alias for PARAM_ALPHANUMEXT, use for various actions in forms and urls * NOTE: originally alias for PARAM_APLHA + * @deprecated since 2.0 */ define('PARAM_ACTION', 'alphanumext'); /** * PARAM_FORMAT - deprecated alias for PARAM_ALPHANUMEXT, use for names of plugins, formats, etc. * NOTE: originally alias for PARAM_APLHA + * @deprecated since 2.0 */ define('PARAM_FORMAT', 'alphanumext'); diff --git a/lib/tests/performance/filtersettingsperformancetester.php b/lib/tests/performance/filtersettingsperformancetester.php index c7122c2dab8..bb387375286 100644 --- a/lib/tests/performance/filtersettingsperformancetester.php +++ b/lib/tests/performance/filtersettingsperformancetester.php @@ -62,7 +62,7 @@ foreach ($requiredtables as $table) { } } -switch (optional_param('action', '', PARAM_ACTION)) { +switch (optional_param('action', '', PARAM_ALPHANUMEXT)) { case 'setup': require_sesskey(); if ($issetup == 0) { diff --git a/mod/glossary/formats.php b/mod/glossary/formats.php index 5d6500974db..2a5764cbda4 100644 --- a/mod/glossary/formats.php +++ b/mod/glossary/formats.php @@ -7,7 +7,7 @@ require_once($CFG->libdir.'/adminlib.php'); require_once("lib.php"); $id = required_param('id', PARAM_INT); -$mode = optional_param('mode', '', PARAM_ACTION); +$mode = optional_param('mode', '', PARAM_ALPHANUMEXT); $url = new moodle_url('/mod/glossary/formats.php', array('id'=>$id)); if ($mode !== '') { diff --git a/mod/lti/typessettings.php b/mod/lti/typessettings.php index 037aa509241..d9c8d9b6a8c 100644 --- a/mod/lti/typessettings.php +++ b/mod/lti/typessettings.php @@ -53,7 +53,7 @@ require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot.'/mod/lti/edit_form.php'); require_once($CFG->dirroot.'/mod/lti/locallib.php'); -$action = optional_param('action', null, PARAM_ACTION); +$action = optional_param('action', null, PARAM_ALPHANUMEXT); $id = optional_param('id', null, PARAM_INT); $tab = optional_param('tab', '', PARAM_ALPHAEXT); diff --git a/mod/wiki/editcomments.php b/mod/wiki/editcomments.php index 5f04d17ddf0..13c9ebc58fb 100644 --- a/mod/wiki/editcomments.php +++ b/mod/wiki/editcomments.php @@ -36,7 +36,7 @@ require_once($CFG->dirroot . '/mod/wiki/locallib.php'); require_once($CFG->dirroot . '/mod/wiki/pagelib.php'); $pageid = required_param('pageid', PARAM_INT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $commentid = optional_param('commentid', 0, PARAM_INT); if (!$page = wiki_get_page($pageid)) { diff --git a/mod/wiki/instancecomments.php b/mod/wiki/instancecomments.php index 731d6dd5381..1294c826c3a 100644 --- a/mod/wiki/instancecomments.php +++ b/mod/wiki/instancecomments.php @@ -38,7 +38,7 @@ require_once($CFG->dirroot . "/mod/wiki/locallib.php"); require_once($CFG->dirroot . '/mod/wiki/comments_form.php'); $pageid = required_param('pageid', PARAM_TEXT); -$action = optional_param('action', '', PARAM_ACTION); +$action = optional_param('action', '', PARAM_ALPHANUMEXT); $id = optional_param('id', 0, PARAM_INT); $commentid = optional_param('commentid', 0, PARAM_INT); $newcontent = optional_param('newcontent', '', PARAM_CLEANHTML); diff --git a/question/type/essay/question.php b/question/type/essay/question.php index 3f3c2c4e284..fa0ed9b2ada 100644 --- a/question/type/essay/question.php +++ b/question/type/essay/question.php @@ -59,7 +59,7 @@ class qtype_essay_question extends question_with_responses { } else { $expecteddata = array('answer' => PARAM_CLEANHTML); } - $expecteddata['answerformat'] = PARAM_FORMAT; + $expecteddata['answerformat'] = PARAM_ALPHANUMEXT; if ($this->attachments != 0) { $expecteddata['attachments'] = question_attempt::PARAM_FILES; } diff --git a/repository/lib.php b/repository/lib.php index c34dec75b7b..2b64c23796e 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -2395,7 +2395,7 @@ final class repository_instance_form extends moodleform { $mform->addElement('hidden', 'edit', ($this->instance) ? $this->instance->id : 0); $mform->setType('edit', PARAM_INT); $mform->addElement('hidden', 'new', $this->plugin); - $mform->setType('new', PARAM_FORMAT); + $mform->setType('new', PARAM_ALPHANUMEXT); $mform->addElement('hidden', 'plugin', $this->plugin); $mform->setType('plugin', PARAM_PLUGIN); $mform->addElement('hidden', 'typeid', $this->typeid); diff --git a/repository/manage_instances.php b/repository/manage_instances.php index 5b5d1c897e8..a6b1363798d 100644 --- a/repository/manage_instances.php +++ b/repository/manage_instances.php @@ -30,7 +30,7 @@ require_once(dirname(dirname(__FILE__)) . '/config.php'); require_once($CFG->dirroot . '/repository/lib.php'); $edit = optional_param('edit', 0, PARAM_INT); -$new = optional_param('new', '', PARAM_FORMAT); +$new = optional_param('new', '', PARAM_ALPHANUMEXT); $delete = optional_param('delete', 0, PARAM_INT); $sure = optional_param('sure', '', PARAM_ALPHA); $contextid = optional_param('contextid', 0, PARAM_INT); diff --git a/user/managetoken.php b/user/managetoken.php index 1c62bd901f9..c8f47b2af88 100644 --- a/user/managetoken.php +++ b/user/managetoken.php @@ -44,7 +44,7 @@ if ( !is_siteadmin($USER->id) && has_capability('moodle/webservice:createtoken', $usercontext )) { require($CFG->dirroot.'/webservice/lib.php'); - $action = optional_param('action', '', PARAM_ACTION); + $action = optional_param('action', '', PARAM_ALPHANUMEXT); $tokenid = optional_param('tokenid', '', PARAM_SAFEDIR); $confirm = optional_param('confirm', 0, PARAM_BOOL); @@ -83,7 +83,7 @@ if ( !is_siteadmin($USER->id) if (!empty($CFG->enablerssfeeds)) { require_once($CFG->dirroot.'/lib/rsslib.php'); - $action = optional_param('action', '', PARAM_ACTION); + $action = optional_param('action', '', PARAM_ALPHANUMEXT); $confirm = optional_param('confirm', 0, PARAM_BOOL); $rssrenderer = $PAGE->get_renderer('core', 'rss'); diff --git a/user/profile/index_category_form.php b/user/profile/index_category_form.php index ee8acc48770..26ab6271b51 100644 --- a/user/profile/index_category_form.php +++ b/user/profile/index_category_form.php @@ -20,7 +20,7 @@ class category_form extends moodleform { $mform->addElement('hidden', 'id'); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'action', 'editcategory'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->addElement('text', 'name', get_string('profilecategoryname', 'admin'), 'maxlength="255" size="30"'); $mform->setType('name', PARAM_MULTILANG); diff --git a/user/profile/index_field_form.php b/user/profile/index_field_form.php index a891504e92f..e5e09a24ae1 100644 --- a/user/profile/index_field_form.php +++ b/user/profile/index_field_form.php @@ -28,7 +28,7 @@ class field_form extends moodleform { $mform->addElement('hidden', 'id'); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'action', 'editfield'); - $mform->setType('action', PARAM_ACTION); + $mform->setType('action', PARAM_ALPHANUMEXT); $mform->addElement('hidden', 'datatype', $datatype); $mform->setType('datatype', PARAM_ALPHA); From afb92f1b9eead59fedf8210ee68709d1488ab1cd Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Mon, 14 May 2012 17:14:15 +0800 Subject: [PATCH 028/106] MDL-31023 libraries: removed deprecated function and classes from pagelib.php --- lang/en/debug.php | 1 - lib/blocklib.php | 29 --- lib/deprecatedlib.php | 14 -- lib/pagelib.php | 414 +----------------------------------------- 4 files changed, 1 insertion(+), 457 deletions(-) diff --git a/lang/en/debug.php b/lang/en/debug.php index a7e25638dce..a18c1bc8586 100644 --- a/lang/en/debug.php +++ b/lang/en/debug.php @@ -41,7 +41,6 @@ $string['missingconfigversion'] = 'Config table does not contain version, can no $string['modulenotexist'] = '{$a} module doesn\'t exist'; $string['morethanonerecordinfetch'] = 'Found more than one record in fetch() !'; $string['mustbeoveride'] = 'Abstract {$a} method must be overridden.'; -$string['noactivityname'] = 'Page object derived from page_generic_activity but did not define $this->activityname'; $string['noadminrole'] = 'No admin role could be found'; $string['noblocks'] = 'No blocks installed!'; $string['nocate'] = 'No categories!'; diff --git a/lib/blocklib.php b/lib/blocklib.php index 1c7097e9246..80834c5d066 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -1960,35 +1960,6 @@ function blocks_delete_all_on_page($pagetype, $pageid) { return false; } -/** - * Dispite what this function is called, it seems to be mostly used to populate - * the default blocks when a new course (or whatever) is created. - * - * @deprecated since 2.0 - * - * @param object $page the page to add default blocks to. - * @return boolean success or failure. - */ -function blocks_repopulate_page($page) { - global $CFG; - - debugging('Call to deprecated function blocks_repopulate_page. ' . - 'Use a more specific method like blocks_add_default_course_blocks, ' . - 'or just call $PAGE->blocks->add_blocks()', DEBUG_DEVELOPER); - - /// If the site override has been defined, it is the only valid one. - if (!empty($CFG->defaultblocks_override)) { - $blocknames = $CFG->defaultblocks_override; - } else { - $blocknames = $page->blocks_get_default(); - } - - $blocks = blocks_parse_default_blocks_list($blocknames); - $page->blocks->add_blocks($blocks); - - return true; -} - /** * Get the block record for a particular blockid - that is, a particular type os block. * diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 714efb884f0..5349be5ec60 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -925,20 +925,6 @@ function current_theme() { return $PAGE->theme->name; } -/** - * @todo Remove this deprecated function when no longer used - * @deprecated since Moodle 2.0 - use $PAGE->pagetype instead of the . - * - * @param string $getid used to return $PAGE->pagetype. - * @param string $getclass used to return $PAGE->legacyclass. - */ -function page_id_and_class(&$getid, &$getclass) { - global $PAGE; - debugging('Call to deprecated function page_id_and_class. Please use $PAGE->pagetype instead.', DEBUG_DEVELOPER); - $getid = $PAGE->pagetype; - $getclass = $PAGE->legacyclass; -} - /** * Prints some red text using echo * diff --git a/lib/pagelib.php b/lib/pagelib.php index ddea0391306..71e4d07ef41 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -650,16 +650,6 @@ class moodle_page { return $this->_devicetypeinuse; } - /** - * Please do not call this method directly, use the ->legacythemeinuse syntax. {@link moodle_page::__get()}. - * @deprecated since 2.1 - * @return bool - */ - protected function magic_get_legacythemeinuse() { - debugging('$PAGE->legacythemeinuse is a deprecated property - please use $PAGE->devicetypeinuse and check if it is equal to legacy.', DEBUG_DEVELOPER); - return ($this->devicetypeinuse == 'legacy'); - } - /** * Please do not call this method directly use the ->periodicrefreshdelay syntax * {@link moodle_page::__get()} @@ -1779,192 +1769,6 @@ class moodle_page { return $caps; } - // Deprecated fields and methods for backwards compatibility ================== - - /** - * Returns the page type. - * - * @deprecated since Moodle 2.0 - use $PAGE->pagetype instead. - * @return string page type. - */ - public function get_type() { - debugging('Call to deprecated method moodle_page::get_type. Please use $PAGE->pagetype instead.'); - return $this->get_pagetype(); - } - - /** - * Returns the page type. - * - * @deprecated since Moodle 2.0 - use $PAGE->pagetype instead. - * @return string this is what page_id_and_class used to return via the $getclass parameter. - */ - public function get_format_name() { - return $this->get_pagetype(); - } - - /** - * Returns the course associated with this page. - * - * @deprecated since Moodle 2.0 - use $PAGE->course instead. - * @return stdClass course. - */ - public function get_courserecord() { - debugging('Call to deprecated method moodle_page::get_courserecord. Please use $PAGE->course instead.'); - return $this->get_course(); - } - - /** - * Returns the legacy page class. - * - * @deprecated since Moodle 2.0 - * @return string this is what page_id_and_class used to return via the $getclass parameter. - */ - public function get_legacyclass() { - if (is_null($this->_legacyclass)) { - $this->initialise_standard_body_classes(); - } - debugging('Call to deprecated method moodle_page::get_legacyclass.'); - return $this->_legacyclass; - } - - /** - * Returns an array of block regions on this page. - * - * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_regions() instead - * @return array the places on this page where blocks can go. - */ - function blocks_get_positions() { - debugging('Call to deprecated method moodle_page::blocks_get_positions. Use $PAGE->blocks->get_regions() instead.'); - return $this->blocks->get_regions(); - } - - /** - * Returns the default block region. - * - * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_default_region() instead - * @return string the default place for blocks on this page. - */ - function blocks_default_position() { - debugging('Call to deprecated method moodle_page::blocks_default_position. Use $PAGE->blocks->get_default_region() instead.'); - return $this->blocks->get_default_region(); - } - - /** - * Returns the default block to use of the page. - * This function no longer does anything. DO NOT USE. - * - * @deprecated since Moodle 2.0 - no longer used. - */ - function blocks_get_default() { - debugging('Call to deprecated method moodle_page::blocks_get_default. This method has no function any more.'); - } - - /** - * Moves a block. - * This function no longer does anything. DO NOT USE. - * - * @deprecated since Moodle 2.0 - no longer used. - */ - function blocks_move_position(&$instance, $move) { - debugging('Call to deprecated method moodle_page::blocks_move_position. This method has no function any more.'); - } - - /** - * Returns the URL parameters for the current page. - * - * @deprecated since Moodle 2.0 - use $this->url->params() instead. - * @return array URL parameters for this page. - */ - function url_get_parameters() { - debugging('Call to deprecated method moodle_page::url_get_parameters. Use $this->url->params() instead.'); - return $this->url->params(); - } - - /** - * Returns the URL path of the current page. - * - * @deprecated since Moodle 2.0 - use $this->url->params() instead. - * @return string URL for this page without parameters. - */ - function url_get_path() { - debugging('Call to deprecated method moodle_page::url_get_path. Use $this->url->out() instead.'); - return $this->url->out(); - } - - /** - * Returns the full URL for this page. - * - * @deprecated since Moodle 2.0 - use $this->url->out() instead. - * @return string full URL for this page. - */ - function url_get_full($extraparams = array()) { - debugging('Call to deprecated method moodle_page::url_get_full. Use $this->url->out() instead.'); - return $this->url->out(true, $extraparams); - } - - /** - * Returns the legacy page object. - * - * @deprecated since Moodle 2.0 - just a backwards compatibility hook. - * @return moodle_page - */ - function set_legacy_page_object($pageobject) { - return $this->_legacypageobject = $pageobject; - } - - /** - * Prints a header... DO NOT USE! - * - * @deprecated since Moodle 2.0 - page objects should no longer be doing print_header. - * @param mixed $_ ... - */ - function print_header($_) { - if (is_null($this->_legacypageobject)) { - throw new coding_exception('You have called print_header on $PAGE when there is not a legacy page class present.'); - } - debugging('You should not longer be doing print_header via a page class.', DEBUG_DEVELOPER); - $args = func_get_args(); - call_user_func_array(array($this->_legacypageobject, 'print_header'), $args); - } - - /** - * Returns the ID for this page. DO NOT USE! - * - * @deprecated since Moodle 2.0 - * @return the 'page id'. This concept no longer exists. - */ - function get_id() { - debugging('Call to deprecated method moodle_page::get_id(). It should not be necessary any more.', DEBUG_DEVELOPER); - if (!is_null($this->_legacypageobject)) { - return $this->_legacypageobject->get_id(); - } - return 0; - } - - /** - * Returns the ID for this page. DO NOT USE! - * - * @deprecated since Moodle 2.0 - * @return the 'page id'. This concept no longer exists. - */ - function get_pageid() { - debugging('Call to deprecated method moodle_page::get_pageid(). It should not be necessary any more.', DEBUG_DEVELOPER); - if (!is_null($this->_legacypageobject)) { - return $this->_legacypageobject->get_id(); - } - return 0; - } - - /** - * Returns the module record for this page. - * - * @deprecated since Moodle 2.0 - user $PAGE->cm instead. - * @return $this->cm; - */ - function get_modulerecord() { - return $this->cm; - } - /** * Returns true if the page URL has beem set. * @@ -2001,220 +1805,4 @@ class moodle_page { public function set_popup_notification_allowed($allowed) { $this->_popup_notification_allowed = $allowed; } -} - -/** - * Not needed any more. DO NOT USE! - * - * @deprecated since Moodle 2.0 - * @param string $path the folder path - * @return array an array of page types. - */ -function page_import_types($path) { - global $CFG; - debugging('Call to deprecated function page_import_types.', DEBUG_DEVELOPER); -} - -/** - * Do not use this any more. The global $PAGE is automatically created for you. - * If you need custom behaviour, you should just set properties of that object. - * - * @deprecated since Moodle 2.0 - * @param integer $instance legacy page instance id. - * @return moodle_page The global $PAGE object. - */ -function page_create_instance($instance) { - global $PAGE; - return page_create_object($PAGE->pagetype, $instance); -} - -/** - * Do not use this any more. The global $PAGE is automatically created for you. - * If you need custom behaviour, you should just set properties of that object. - * - * @deprecated since Moodle 2.0 - * @return moodle_page The global $PAGE object. - */ -function page_create_object($type, $id = NULL) { - global $CFG, $PAGE, $SITE, $ME; - debugging('Call to deprecated function page_create_object.', DEBUG_DEVELOPER); - - $data = new stdClass; - $data->pagetype = $type; - $data->pageid = $id; - - $classname = page_map_class($type); - if (!$classname) { - return $PAGE; - } - $legacypage = new $classname; - $legacypage->init_quick($data); - - $course = $PAGE->course; - if ($course->id != $SITE->id) { - $legacypage->set_course($course); - } else { - try { - $category = $PAGE->category; - } catch (coding_exception $e) { - // Was not set before, so no need to try to set it again. - $category = false; - } - if ($category) { - $legacypage->set_category_by_id($category->id); - } else { - $legacypage->set_course($SITE); - } - } - - $legacypage->set_pagetype($type); - - $legacypage->set_url($ME); - $PAGE->set_url(str_replace($CFG->wwwroot . '/', '', $legacypage->url_get_full())); - - $PAGE->set_pagetype($type); - $PAGE->set_legacy_page_object($legacypage); - return $PAGE; -} - -/** - * You should not be writing page subclasses any more. Just set properties on the - * global $PAGE object to control its behaviour. - * - * @deprecated since Moodle 2.0 - * @return mixed Null if there is not a valid page mapping, or the mapping if - * it has been set. - */ -function page_map_class($type, $classname = NULL) { - global $CFG; - - static $mappings = array( - PAGE_COURSE_VIEW => 'page_course', - ); - - if (!empty($type) && !empty($classname)) { - $mappings[$type] = $classname; - } - - if (!isset($mappings[$type])) { - debugging('Page class mapping requested for unknown type: '.$type); - return null; - } else if (empty($classname) && !class_exists($mappings[$type])) { - debugging('Page class mapping for id "'.$type.'" exists but class "'.$mappings[$type].'" is not defined'); - return null; - } - - return $mappings[$type]; -} - -/** - * Parent class from which all Moodle page classes derive - * - * @deprecated since Moodle 2.0 - * @package core - * @category page - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class page_base extends moodle_page { - /** - * @var int The numeric identifier of the page being described. - */ - public $id = null; - - /** - * Returns the page id - * @deprecated since Moodle 2.0 - * @return int Returns the id of the page. - */ - public function get_id() { - return $this->id; - } - - /** - * Initialize the data members of the parent class - * @param scalar $data - */ - public function init_quick($data) { - $this->id = $data->pageid; - } - - /** - * DOES NOTHING... DO NOT USE. - * @deprecated since Moodle 2.0 - */ - public function init_full() {} -} - -/** - * Class that models the behavior of a moodle course. - * Although this does nothing, this class declaration should be left for now - * since there may be legacy class doing class page_... extends page_course - * - * @deprecated since Moodle 2.0 - * @package core - * @category page - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class page_course extends page_base {} - -/** - * Class that models the common parts of all activity modules - * - * @deprecated since Moodle 2.0 - * @package core - * @category page - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class page_generic_activity extends page_base { - - /** - * Although this function is deprecated, it should be left here because - * people upgrading legacy code need to copy it. See - * http://docs.moodle.org/dev/Migrating_your_code_to_the_2.0_rendering_API - * - * @param string $title - * @param array $morenavlinks - * @param string $bodytags - * @param string $meta - */ - function print_header($title, $morenavlinks = NULL, $bodytags = '', $meta = '') { - global $USER, $CFG, $PAGE, $OUTPUT; - - $this->init_full(); - $replacements = array( - '%fullname%' => format_string($this->activityrecord->name) - ); - foreach ($replacements as $search => $replace) { - $title = str_replace($search, $replace, $title); - } - - $buttons = ''; - if ($this->user_allowed_editing()) { - $buttons .= ''; - } - $buttons .= '
'.$OUTPUT->update_module_button($this->modulerecord->id, $this->activityname).'
'. - ''. - ''. - '
'; - - if (!empty($morenavlinks) && is_array($morenavlinks)) { - foreach ($morenavlinks as $navitem) { - if (is_array($navitem) && array_key_exists('name', $navitem)) { - $link = null; - if (array_key_exists('link', $navitem)) { - $link = $navitem['link']; - } - $PAGE->navbar->add($navitem['name'], $link); - } - } - } - - $PAGE->set_title($title); - $PAGE->set_heading($this->course->fullname); - $PAGE->set_button($buttons); - echo $OUTPUT->header(); - } -} +} \ No newline at end of file From 11ad98ff0c1aac50bde552221adba0ff91d9967a Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Thu, 19 Jul 2012 14:33:31 +0800 Subject: [PATCH 029/106] MDL-31023 Libraries: removed legacypageobject usage --- lib/pagelib.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/pagelib.php b/lib/pagelib.php index 71e4d07ef41..7c55efd7e11 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -312,14 +312,6 @@ class moodle_page { */ protected $_periodicrefreshdelay = null; - /** - * @var stdClass This is simply to improve backwards compatibility. If old - * code relies on a page class that implements print_header, or complex logic - * in user_allowed_editing then we stash an instance of that other class here, - * and delegate to it in certain situations. - */ - protected $_legacypageobject = null; - /** * @var array Associative array of browser shortnames (as used by check_browser_version) * and their minimum required versions @@ -792,9 +784,6 @@ class moodle_page { * @return bool */ public function user_allowed_editing() { - if ($this->_legacypageobject) { - return $this->_legacypageobject->user_allowed_editing(); - } return has_any_capability($this->all_editing_caps(), $this->_context); } @@ -1158,9 +1147,6 @@ class moodle_page { if (is_null($this->_pagetype)) { $this->initialise_default_pagetype($shorturl); } - if (!is_null($this->_legacypageobject)) { - $this->_legacypageobject->set_url($url, $params); - } } /** From 1868607ad6969221c26893db54f6a4953c3d5369 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 17 Jul 2012 09:22:48 +0800 Subject: [PATCH 030/106] MDL-34265 SCORM: Removing sorting from unsortable columns --- mod/scorm/report/interactions/report.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mod/scorm/report/interactions/report.php b/mod/scorm/report/interactions/report.php index 38a250650ad..0756ebd2898 100644 --- a/mod/scorm/report/interactions/report.php +++ b/mod/scorm/report/interactions/report.php @@ -221,6 +221,18 @@ class scorm_interactions_report extends scorm_default_report { $table->no_sorting('finish'); $table->no_sorting('score'); + for($id = 0; $id < $questioncount; $id++) { + if ($displayoptions['qtext']) { + $table->no_sorting('question'.$id); + } + if ($displayoptions['resp']) { + $table->no_sorting('response'.$id); + } + if ($displayoptions['right']) { + $table->no_sorting('right'.$id); + } + } + foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde'.$sco->id); From fc9ae8d1643324fcee5792ee53bf545080373cd0 Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Thu, 19 Jul 2012 15:04:53 +0800 Subject: [PATCH 031/106] MDL-31294 Forms Library: Removed deprecated file and format form element --- lib/form/file.php | 109 -------------------------------------------- lib/form/format.php | 59 ------------------------ lib/formslib.php | 2 - 3 files changed, 170 deletions(-) delete mode 100644 lib/form/file.php delete mode 100644 lib/form/format.php diff --git a/lib/form/file.php b/lib/form/file.php deleted file mode 100644 index 259881b5042..00000000000 --- a/lib/form/file.php +++ /dev/null @@ -1,109 +0,0 @@ -. - - -/** - * File type form element - * - * Contains HTML class for a file type form element - * - * @package core_form - * @copyright 2007 Jamie Pratt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -require_once('HTML/QuickForm/file.php'); - -/** - * file element - * - * HTML class for a form element to upload a file - * - * @package core_form - * @deprecated since Moodle 2.0 Please do not use this form element. - * @todo MDL-31294 remove this element - * @see MoodleQuickForm_filepicker - * @see MoodleQuickForm_filemanager - * @copyright 2007 Jamie Pratt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class MoodleQuickForm_file extends HTML_QuickForm_file{ - /** @var string html for help button, if empty then no help */ - var $_helpbutton=''; - - /** - * Constructor - * - * @param string $elementName (optional) name of the editor - * @param string $elementLabel (optional) editor label - * @param array $attributes (optional) Either a typical HTML attribute string - * or an associative array - */ - function MoodleQuickForm_file($elementName=null, $elementLabel=null, $attributes=null) { - debugging('file forms element is deprecated, please use new filepicker instead'); - parent::HTML_QuickForm_file($elementName, $elementLabel, $attributes); - } - /** - * set html for help button - * - * @param array $helpbuttonargs array of arguments to make a help button - * @param string $function function name to call to get html - * @deprecated since Moodle 2.0. Please do not call this function any more. - * @todo MDL-31047 this api will be removed. - * @see MoodleQuickForm::setHelpButton() - */ - function setHelpButton($helpbuttonargs, $function='helpbutton'){ - debugging('component setHelpButton() is not used any more, please use $mform->setHelpButton() instead'); - } - /** - * set html for help button - */ - function getHelpButton(){ - return $this->_helpbutton; - } - - /** - * Override createElement event to add max files - * - * @param string $event Name of event - * @param mixed $arg event arguments - * @param object $caller calling object - * @return bool - */ - function onQuickFormEvent($event, $arg, &$caller) - { - if ($event == 'createElement') { - $className = get_class($this); - $this->$className($arg[0], $arg[1].' ('.get_string('maxsize', '', display_size($caller->getMaxFileSize())).')', $arg[2]); - return true; - } - return parent::onQuickFormEvent($event, $arg, $caller); - } - - /** - * Slightly different container template when frozen. - * - * @return string - */ - function getElementTemplateType(){ - if ($this->_flagFrozen){ - return 'static'; - } else { - return 'default'; - } - } - -} \ No newline at end of file diff --git a/lib/form/format.php b/lib/form/format.php deleted file mode 100644 index ef55aae33c5..00000000000 --- a/lib/form/format.php +++ /dev/null @@ -1,59 +0,0 @@ -. - - -/** - * editor format form element - * - * Contains HTML class for a editor format drop down element - * - * @package core_form - * @copyright 2007 Jamie Pratt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -global $CFG; -require_once "$CFG->libdir/form/select.php"; - -/** - * editor format form element - * - * HTML class for a editor format drop down element - * - * @package core_form - * @copyright 2007 Jamie Pratt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @deprecated since Moodle 2.0 Please do not use this form element. - * @todo MDL-31294, remove this element - * @see MoodleQuickForm_editor - */ -class MoodleQuickForm_format extends MoodleQuickForm_select{ - - /** - * Class constructor - * - * @param string $elementName Select name attribute - * @param mixed $elementLabel Label(s) for the select - * @param mixed $attributes Either a typical HTML attribute string or an associative array - * @param mixed $useHtmlEditor Either a string returned from can_use_html_editor() or false for no html editor - * default 'detect' tells element to use html editor if it is available. - */ - function MoodleQuickForm_format($elementName=null, $elementLabel=null, $attributes=null, $useHtmlEditor=null) - { - throw new coding_exception('MFORMS: Coding error, text formats are handled only by new editor element.'); - } //end constructor - -} diff --git a/lib/formslib.php b/lib/formslib.php index 72003796eca..129c2140bf5 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -2562,10 +2562,8 @@ MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/datesel MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector'); MoodleQuickForm::registerElementType('duration', "$CFG->libdir/form/duration.php", 'MoodleQuickForm_duration'); MoodleQuickForm::registerElementType('editor', "$CFG->libdir/form/editor.php", 'MoodleQuickForm_editor'); -MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file'); MoodleQuickForm::registerElementType('filemanager', "$CFG->libdir/form/filemanager.php", 'MoodleQuickForm_filemanager'); MoodleQuickForm::registerElementType('filepicker', "$CFG->libdir/form/filepicker.php", 'MoodleQuickForm_filepicker'); -MoodleQuickForm::registerElementType('format', "$CFG->libdir/form/format.php", 'MoodleQuickForm_format'); MoodleQuickForm::registerElementType('grading', "$CFG->libdir/form/grading.php", 'MoodleQuickForm_grading'); MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); MoodleQuickForm::registerElementType('header', "$CFG->libdir/form/header.php", 'MoodleQuickForm_header'); From 2ede466e5faa800511b2dc04995cad61b7cc88f7 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Fri, 13 Jul 2012 13:49:09 +1200 Subject: [PATCH 032/106] MDL-34286 conditionlib: Fixed up loading of user profile data for custom field conditions --- lib/conditionlib.php | 160 ++++++++++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 64 deletions(-) diff --git a/lib/conditionlib.php b/lib/conditionlib.php index 650006a0288..44d65005bc6 100644 --- a/lib/conditionlib.php +++ b/lib/conditionlib.php @@ -374,7 +374,8 @@ abstract class condition_info_base { protected $idfieldname; /** @var array */ protected $usergroupings; - + /** @var array An array of custom profile field ids => to their shortname */ + protected $customprofilefields = null; /** * Constructs with item details. * @@ -1002,8 +1003,8 @@ abstract class condition_info_base { // Check if user field condition if (count($this->item->conditionsfield) > 0) { foreach ($this->item->conditionsfield as $field => $details) { - $uservalue = $this->get_cached_user_profile_field($userid, $field, $grabthelot); - if (!$fieldconditionmet = $this->is_field_condition_met($details->operator, $uservalue, $details->value)) { + $uservalue = $this->get_cached_user_profile_field($userid, $field); + if (!$this->is_field_condition_met($details->operator, $uservalue, $details->value)) { // Set available to false $available = false; $a = new stdClass(); @@ -1185,7 +1186,15 @@ abstract class condition_info_base { * @return boolean */ private function is_field_condition_met($operator, $uservalue, $value) { + if ($uservalue === false) { + // If the user value is false this is an instant fail. + // All user values come from the database as either data or the default. + // They will always be a string. + return false; + } $fieldconditionmet = true; + // Just to be doubly sure it is a string. + $uservalue = (string)$uservalue; switch($operator) { case OP_CONTAINS: // contains $pos = strpos($uservalue, $value); @@ -1233,71 +1242,94 @@ abstract class condition_info_base { * * @param int $userid set if requesting grade for a different user (does not use cache) * @param int $fieldid the user profile field id - * @param bool $grabthelot If true, grabs all the user profile fields for current user on this course, so that later ones come from cache * @return string the user value, or false if user does not have a user field value yet */ - private function get_cached_user_profile_field($userid, $fieldid, $grabthelot) { - global $USER, $DB, $SESSION; - // Check if the field is a custom profile field - $iscustomprofilefield = is_numeric($fieldid) ? true : false; - if ($userid == 0 || $userid == $USER->id) { - if ($iscustomprofilefield) { - // For current user, go via cache in session - if (empty($SESSION->userfieldcache) || $SESSION->userfieldcacheuserid != $USER->id) { - $SESSION->userfieldcache = array(); - $SESSION->userfieldcacheuserid = $USER->id; - } - if (!array_key_exists($fieldid, $SESSION->userfieldcache)) { - if ($grabthelot) { - // Get all custom profile field values for user - $sql = "SELECT uf.id, ud.data - FROM {user_info_field} uf - LEFT JOIN {user_info_data} ud ON uf.id = ud.fieldid - WHERE ud.userid = :userid"; - if ($records = $DB->get_records_sql($sql, array('userid' => $USER->id))) { - foreach ($records as $r) { - $SESSION->userfieldcache[$r->id] = $r->data; - } - } - } else { - // Just get specified user field - $sql = "SELECT ud.data - FROM {user_info_data} ud - INNER JOIN {user_info_field} uf ON ud.fieldid = uf.id - WHERE uf.id = :fieldid - AND ud.userid = :userid"; - if ($record = $DB->get_record_sql($sql, array('fieldid' => $fieldid, 'userid' => $USER->id))) { - $field = $record->data; - } else { - $field = false; - } - $SESSION->userfieldcache[$fieldid] = $field; - } - } - if (!empty($SESSION->userfieldcache[$fieldid])) { - return $SESSION->userfieldcache[$fieldid]; - } else { - return false; - } - } else { - return $USER->$fieldid; - } - } else { - if ($iscustomprofilefield) { - $sql = "SELECT ud.data - FROM {user_info_data} ud - INNER JOIN {user_info_field} uf ON ud.fieldid = uf.id - WHERE uf.id = :fieldid - AND ud.userid = :userid"; - if ($record = $DB->get_record_sql($sql, array('fieldid' => $fieldid, 'userid' => $userid))) { - return $record->data; - } - } else { - return $DB->get_field('user', $fieldid, array('id' => $userid), MUST_EXIST); - } - // If it reaches here, then no matches found + private function get_cached_user_profile_field($userid, $fieldid) { + global $USER, $DB, $CFG; + + if ($userid === 0) { + // Map out userid = 0 to the current user + $userid = $USER->id; + } + $iscurrentuser = $USER->id == $userid; + + if (isguestuser($userid)) { + // Must be logged in and can't be the guest. (this should never happen anyway) return false; } + + // Custom profile fields will be numeric, there are no numeric standard profile fields so this is not a problem. + $iscustomprofilefield = is_numeric($fieldid); + if ($iscustomprofilefield) { + // As its a custom profile field we need to map the id back to the actual field. + // We'll also preload all of the other custom profile fields just in case and ensure we have the + // default value available as well. + if ($this->customprofilefields === null) { + $this->customprofilefields = $DB->get_records('user_info_field', null, 'sortorder ASC, id ASC', 'id, shortname, defaultdata'); + } + if (!array_key_exists($fieldid, $this->customprofilefields)) { + // No such field exists. + // This shouldn't normally happen but occur if things go wrong when deleting a custom profile field + // or when restoring a backup of a course with user profile field conditions. + return false; + } + $field = $this->customprofilefields[$fieldid]->shortname; + } else { + $field = $fieldid; + } + + // If its the current user than most likely we will be able to get this information from $USER. + // If its a regular profile field then it should already be available, if not then we have a mega problem. + // If its a custom profile field then it should be available but may not be. If it is then we use the value + // available, otherwise we load all custom profile fields into a temp object and refer to that. + // Noting its not going be great for performance if we have to use the temp object as it involves loading the + // custom profile field API and classes. + if ($iscurrentuser) { + if (!$iscustomprofilefield) { + if (property_exists($USER, $field)) { + return $USER->{$field}; + } else { + // Unknown user field. This should not happen. + throw new coding_exception('Requested user profile field does not exist'); + } + } + // Checking if the custom profile fields are already available. + if (!isset($USER->profile)) { + // Drat! they're not. We need to use a temp object and load them. + // We don't use $USER as the profile fields are loaded into the object. + $user = new stdClass; + $user->id = $USER->id; + // This should ALWAYS be set, but just in case we check. + require_once($CFG->dirroot.'/user/profile/lib.php'); + profile_load_custom_fields($user); + if (array_key_exists($field, $user->profile)) { + return $user->profile[$field]; + } + } else if (array_key_exists($field, $USER->profile)) { + // Hurrah they're available, this is easy. + return $USER->profile[$field]; + } + // The profile field doesn't exist. + return false; + } else { + // Loading for another user. + if ($iscustomprofilefield) { + // Fetch the data for the field. Noting we keep this query simple so that Database caching takes care of performance + // for us (this will likely be hit again). + // We are able to do this because we've already pre-loaded the custom fields. + $data = $DB->get_field('user_info_data', 'data', array('userid' => $userid, 'fieldid' => $fieldid), IGNORE_MISSING); + // If we have data return that, otherwise return the default. + if ($data !== false) { + return $data; + } else { + return $this->customprofilefields[$field]->defaultdata; + } + } else { + // Its a standard field, retrieve it from the user. + return $DB->get_field('user', $field, array('id' => $userid), MUST_EXIST); + } + } + return false; } /** From dd51b3b2e0dd4cebe922493f1e726e54dcade318 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Thu, 12 Jul 2012 11:27:46 +1200 Subject: [PATCH 033/106] MDL-33448 javascript: Added caching for the YUI instance used for debug in get_string --- lib/javascript-static.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/javascript-static.js b/lib/javascript-static.js index 66af6218bd0..463f8249616 100644 --- a/lib/javascript-static.js +++ b/lib/javascript-static.js @@ -716,7 +716,13 @@ M.util.get_string = function(identifier, component, a) { // creating new instance if YUI is not optimal but it seems to be better way then // require the instance via the function API - note that it is used in rare cases // for debugging only anyway - var Y = new YUI({ debug : true }); + // To ensure we don't kill browser performance if hundreds of get_string requests + // are made we cache the instance we generate within the M.util namespace. + // We don't publicly define the variable so that it doesn't get abused. + if (typeof M.util.get_string_yui_instance === 'undefined') { + M.util.get_string_yui_instance = new YUI({ debug : true }); + } + var Y = M.util.get_string_yui_instance; } if (!M.str.hasOwnProperty(component) || !M.str[component].hasOwnProperty(identifier)) { From a3e6ad77d272207752b5144605a123e544303f66 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Wed, 27 Jun 2012 16:17:36 +0100 Subject: [PATCH 034/106] MDL-34066 adaptive behaviour: refactor logic out of renderer. These changes move the logic to the behaviour class, which is how things should be. It also makes it easier to re-use the code that displays the messages like "Marks for this submission: 1.00/1.00. Accounting for previous tries, this gives 0.33/1.00." in other places. To try to make it clearer what is going on, I introduced a new class qbehaviour_adaptive_mark_details to hold and document the data that the behaviour needs to return, and the renderer can base its display on. As far as my testing can tell (and there are new unit tests), this commit does not change the existing behaviour. This commit also replaces all the string concatenation that is going on, which should help translators. At the moment, a few of the old strings are still in the language file, and are used in the unit tests to verify that the behaviour has not changed. Thanks to Oleg Sychev for making a helpful suggestion about the API. --- question/behaviour/adaptive/behaviour.php | 112 ++++++++++++++++++ .../adaptive/lang/en/qbehaviour_adaptive.php | 12 +- question/behaviour/adaptive/renderer.php | 104 +++++++--------- .../adaptive/tests/mark_display_test.php | 110 +++++++++++++++++ .../behaviour/adaptivenopenalty/renderer.php | 3 +- 5 files changed, 277 insertions(+), 64 deletions(-) create mode 100644 question/behaviour/adaptive/tests/mark_display_test.php diff --git a/question/behaviour/adaptive/behaviour.php b/question/behaviour/adaptive/behaviour.php index e85bc6815b0..84bcd0b7c88 100644 --- a/question/behaviour/adaptive/behaviour.php +++ b/question/behaviour/adaptive/behaviour.php @@ -216,4 +216,116 @@ class qbehaviour_adaptive extends question_behaviour_with_save { public function is_state_improvable(question_state $state) { return $state == question_state::$todo; } + + /** + * @return qbehaviour_adaptive_mark_details the information about the current state-of-play, scoring-wise, + * for this adaptive attempt. + */ + public function get_adaptive_marks() { + + // Try to find the last graded step. + $gradedstep = $this->get_graded_step(); + if (is_null($gradedstep) || $this->qa->get_max_mark() == 0) { + // No score yet. + return new qbehaviour_adaptive_mark_details(question_state::$todo); + } + + // Work out the applicable state. + if ($this->qa->get_state()->is_commented()) { + $state = $this->qa->get_state(); + } else { + $state = question_state::graded_state_for_fraction( + $gradedstep->get_behaviour_var('_rawfraction')); + } + + // Prepare the grading details. + $details = $this->adaptive_mark_details_from_step($gradedstep, $state, $this->qa->get_max_mark(), $this->question->penalty); + $details->improvable = $this->is_state_improvable($this->qa->get_state()); + return $details; + } + + /** + * Actually populate the qbehaviour_adaptive_mark_details object. + * @param question_attempt_step $gradedstep the step that holds the relevant mark details. + * @param question_state $state the state corresponding to $gradedstep. + * @param unknown_type $maxmark the maximum mark for this question_attempt. + * @param unknown_type $penalty the penalty for this question, as a fraction. + */ + protected function adaptive_mark_details_from_step(question_attempt_step $gradedstep, + question_state $state, $maxmark, $penalty) { + + $details = new qbehaviour_adaptive_mark_details($state); + $details->maxmark = $maxmark; + $details->actualmark = $gradedstep->get_fraction() * $details->maxmark; + $details->rawmark = $gradedstep->get_behaviour_var('_rawfraction') * $details->maxmark; + + $details->currentpenalty = $penalty * $details->maxmark; + $details->totalpenalty = $details->currentpenalty * $this->qa->get_last_behaviour_var('_try', 0); + + $details->improvable = $this->is_state_improvable($gradedstep->get_state()); + + return $details; + } +} + + +/** + * This class encapsulates all the information about the current state-of-play + * scoring-wise. It is used to communicate between the beahviour and the renderer. + * + * @copyright 2012 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class qbehaviour_adaptive_mark_details { + /** @var question_state the current state of the question. */ + public $state; + + /** @var float the maximum mark for this question. */ + public $maxmark; + + /** @var float the current mark for this question. */ + public $actualmark; + + /** @var float the raw mark for this question before penalties were applied. */ + public $rawmark; + + /** @var float the the amount of additional penalty this attempt attracted. */ + public $currentpenalty; + + /** @var float the total that will apply to future attempts. */ + public $totalpenalty; + + /** @var bool whether it is possible for this mark to be improved in future. */ + public $improvable; + + /** + * Constructor. + * @param question_state $state + */ + public function __construct($state, $maxmark = null, $actualmark = null, $rawmark = null, + $currentpenalty = null, $totalpenalty = null, $improvable = null) { + $this->state = $state; + $this->maxmark = $maxmark; + $this->actualmark = $actualmark; + $this->rawmark = $rawmark; + $this->currentpenalty = $currentpenalty; + $this->totalpenalty = $totalpenalty; + $this->improvable = $improvable; + } + + /** + * Get the marks, formatted to a certain number of decimal places, in the + * form required by calls like get_string('gradingdetails', 'qbehaviour_adaptive', $a). + * @param int $markdp the number of decimal places required. + * @return array ready to substitute into language strings. + */ + public function get_formatted_marks($markdp) { + return array( + 'max' => format_float($this->maxmark, $markdp), + 'cur' => format_float($this->actualmark, $markdp), + 'raw' => format_float($this->rawmark, $markdp), + 'penalty' => format_float($this->currentpenalty, $markdp), + 'totalpenalty' => format_float($this->totalpenalty, $markdp), + ); + } } diff --git a/question/behaviour/adaptive/lang/en/qbehaviour_adaptive.php b/question/behaviour/adaptive/lang/en/qbehaviour_adaptive.php index 6c415de1836..2dc2e53bc66 100644 --- a/question/behaviour/adaptive/lang/en/qbehaviour_adaptive.php +++ b/question/behaviour/adaptive/lang/en/qbehaviour_adaptive.php @@ -25,8 +25,16 @@ $string['disregardedwithoutpenalty'] = 'The submission was invalid, and has been disregarded without penalty.'; $string['gradingdetails'] = 'Marks for this submission: {$a->raw}/{$a->max}.'; +$string['gradingdetailswithadjustment'] = 'Marks for this submission: {$a->raw}/{$a->max}. Accounting for previous tries, this gives {$a->cur}/{$a->max}.'; +$string['gradingdetailswithadjustmentpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. Accounting for previous tries, this gives {$a->cur}/{$a->max}. This submission attracted a penalty of {$a->penalty}.'; +$string['gradingdetailswithadjustmenttotalpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. Accounting for previous tries, this gives {$a->cur}/{$a->max}. This submission attracted a penalty of {$a->penalty}. Total penalties so far: {$a->totalpenalty}.'; +$string['gradingdetailswithpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. This submission attracted a penalty of {$a->penalty}.'; +$string['gradingdetailswithtotalpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. This submission attracted a penalty of {$a->penalty}. Total penalties so far: {$a->totalpenalty}.'; +$string['notcomplete'] = 'Not complete'; +$string['pluginname'] = 'Adaptive mode'; + +// Old strings these are currently only used in the unit tests, to verify that the new +// strings give the same results as the old strings. $string['gradingdetailsadjustment'] = 'Accounting for previous tries, this gives {$a->cur}/{$a->max}.'; $string['gradingdetailspenalty'] = 'This submission attracted a penalty of {$a}.'; $string['gradingdetailspenaltytotal'] = 'Total penalties so far: {$a}.'; -$string['notcomplete'] = 'Not complete'; -$string['pluginname'] = 'Adaptive mode'; diff --git a/question/behaviour/adaptive/renderer.php b/question/behaviour/adaptive/renderer.php index aa88f9b46c0..3c1f90f8260 100644 --- a/question/behaviour/adaptive/renderer.php +++ b/question/behaviour/adaptive/renderer.php @@ -42,85 +42,70 @@ class qbehaviour_adaptive_renderer extends qbehaviour_renderer { } public function feedback(question_attempt $qa, question_display_options $options) { + + // If the latest answer was invalid, display an informative message. if ($qa->get_state() == question_state::$invalid) { - // If the latest answer was invalid, display an informative message - $output = ''; - $info = $this->disregarded_info(); - if ($info) { - $output = html_writer::tag('div', $info, array('class' => 'gradingdetails')); - } - return $output; + return html_writer::nonempty_tag('div', $this->disregarded_info(), + array('class' => 'gradingdetails')); } - // Try to find the last graded step. + // Otherwise get the details. + return $this->render_adaptive_marks( + $qa->get_behaviour()->get_adaptive_marks(), $options); + } - $gradedstep = $qa->get_behaviour()->get_graded_step($qa); - if (is_null($gradedstep) || $qa->get_max_mark() == 0 || - $options->marks < question_display_options::MARK_AND_MAX) { + /** + * Display the scoring information about an adaptive attempt. + * @param qbehaviour_adaptive_mark_details contains all the score details we need. + * @param question_display_options $options display options. + */ + public function render_adaptive_marks(qbehaviour_adaptive_mark_details $details, question_display_options $options) { + if ($details->state == question_state::$todo || $options->marks < question_display_options::MARK_AND_MAX) { + // No grades yet. return ''; } - // Display the grading details from the last graded state - $mark = new stdClass(); - $mark->max = $qa->format_max_mark($options->markdp); - - $actualmark = $gradedstep->get_fraction() * $qa->get_max_mark(); - $mark->cur = format_float($actualmark, $options->markdp); - - $rawmark = $gradedstep->get_behaviour_var('_rawfraction') * $qa->get_max_mark(); - $mark->raw = format_float($rawmark, $options->markdp); - - // let student know wether the answer was correct - if ($qa->get_state()->is_commented()) { - $class = $qa->get_state()->get_feedback_class(); - } else { - $class = question_state::graded_state_for_fraction( - $gradedstep->get_behaviour_var('_rawfraction'))->get_feedback_class(); - } - - $gradingdetails = get_string('gradingdetails', 'qbehaviour_adaptive', $mark); - - $gradingdetails .= $this->penalty_info($qa, $mark, $options); - - $output = ''; - $output .= html_writer::tag('div', get_string($class, 'question'), - array('class' => 'correctness ' . $class)); - $output .= html_writer::tag('div', $gradingdetails, - array('class' => 'gradingdetails')); - return $output; + // Display the grading details from the last graded state. + $class = $details->state->get_feedback_class(); + return html_writer::tag('div', get_string($class, 'question'), + array('class' => 'correctness ' . $class)) + . html_writer::tag('div', $this->grading_details($details, $options), + array('class' => 'gradingdetails')); } /** * Display the information about the penalty calculations. - * @param question_attempt $qa the question attempt. - * @param object $mark contains information about the current mark. + * @param qbehaviour_adaptive_mark_details contains all the score details we need. * @param question_display_options $options display options. + * @return string html fragment */ - protected function penalty_info(question_attempt $qa, $mark, - question_display_options $options) { + protected function grading_details(qbehaviour_adaptive_mark_details $details, question_display_options $options) { - $currentpenalty = $qa->get_question()->penalty * $qa->get_max_mark(); - $totalpenalty = $currentpenalty * $qa->get_last_behaviour_var('_try', 0); + $mark = $details->get_formatted_marks($options->markdp); - if ($currentpenalty == 0) { - return ''; + if ($details->currentpenalty == 0 && $details->totalpenalty == 0) { + return get_string('gradingdetails', 'qbehaviour_adaptive', $mark); } + $output = ''; // Print details of grade adjustment due to penalties - if ($mark->raw != $mark->cur) { - $output .= ' ' . get_string('gradingdetailsadjustment', 'qbehaviour_adaptive', $mark); - } + if ($details->rawmark != $details->actualmark) { + if (!$details->improvable) { + return get_string('gradingdetailswithadjustment', 'qbehaviour_adaptive', $mark); + } else if ($details->totalpenalty > $details->currentpenalty) { + return get_string('gradingdetailswithadjustmenttotalpenalty', 'qbehaviour_adaptive', $mark); + } else { + return get_string('gradingdetailswithadjustmentpenalty', 'qbehaviour_adaptive', $mark); + } - // Print information about any new penalty, only relevant if the answer can be improved. - if ($qa->get_behaviour()->is_state_improvable($qa->get_state())) { - $output .= ' ' . get_string('gradingdetailspenalty', 'qbehaviour_adaptive', - format_float($currentpenalty, $options->markdp)); - - // Print information about total penalties so far, if larger than current penalty. - if ($totalpenalty > $currentpenalty) { - $output .= ' ' . get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive', - format_float($totalpenalty, $options->markdp)); + } else { + if (!$details->improvable) { + return get_string('gradingdetails', 'qbehaviour_adaptive', $mark); + } else if ($details->totalpenalty > $details->currentpenalty) { + return get_string('gradingdetailswithtotalpenalty', 'qbehaviour_adaptive', $mark); + } else { + return get_string('gradingdetailswithpenalty', 'qbehaviour_adaptive', $mark); } } @@ -133,5 +118,4 @@ class qbehaviour_adaptive_renderer extends qbehaviour_renderer { protected function disregarded_info() { return get_string('disregardedwithoutpenalty', 'qbehaviour_adaptive'); } - } diff --git a/question/behaviour/adaptive/tests/mark_display_test.php b/question/behaviour/adaptive/tests/mark_display_test.php new file mode 100644 index 00000000000..f77fdc9ecae --- /dev/null +++ b/question/behaviour/adaptive/tests/mark_display_test.php @@ -0,0 +1,110 @@ +. + + +/** + * This file contains tests that just test the display mark/penalty information. + * + * @package qbehaviour_adaptive + * @copyright 2012 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once(dirname(__FILE__) . '/../../../engine/lib.php'); +require_once(dirname(__FILE__) . '/../behaviour.php'); + + +/** + * Unit tests for the adaptive behaviour the display of mark/penalty information. + * + * @copyright 2012 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class qbehaviour_adaptive_mark_display_test extends basic_testcase { + /** @var qbehaviour_adaptive_renderer the renderer to test. */ + protected $renderer; + + /** @var question_display_options display options to use when rendering. */ + protected $options; + + protected function setUp() { + global $PAGE; + parent::setUp(); + $this->renderer = $PAGE->get_renderer('qbehaviour_adaptive'); + $this->options = new question_display_options(); + } + + public function test_blank_before_graded() { + $this->assertEquals('', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$todo), $this->options)); + } + + public function test_correct_no_penalty() { + $this->assertEquals('
' . get_string('correct', 'question') . '
' . + '
' . + get_string('gradingdetails', 'qbehaviour_adaptive', + array('cur' => '1.00', 'raw' => '1.00', 'max' => '1.00')) . '
', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$gradedright, 1, 1, 1, 0, 0, false), $this->options)); + } + + public function test_partial_first_try() { + $this->assertEquals('
' . get_string('partiallycorrect', 'question') . '
' . + '
' . + get_string('gradingdetails', 'qbehaviour_adaptive', + array('cur' => '0.50', 'raw' => '0.50', 'max' => '1.00')) . ' ' . + get_string('gradingdetailspenalty', 'qbehaviour_adaptive', '0.10') . '
', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$gradedpartial, 1, 0.5, 0.5, 0.1, 0.1, true), $this->options)); + } + + public function test_partial_second_try() { + $mark = array('cur' => '0.80', 'raw' => '0.90', 'max' => '1.00'); + $this->assertEquals('
' . get_string('partiallycorrect', 'question') . '
' . + '
' . + get_string('gradingdetails', 'qbehaviour_adaptive', $mark) . ' ' . + get_string('gradingdetailsadjustment', 'qbehaviour_adaptive', $mark) . ' ' . + get_string('gradingdetailspenalty', 'qbehaviour_adaptive', '0.10') . ' ' . + get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive', '0.20') . '
', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$gradedpartial, 1, 0.8, 0.9, 0.1, 0.2, true), $this->options)); + } + + public function test_correct_third_try() { + $mark = array('cur' => '0.80', 'raw' => '1.00', 'max' => '1.00'); + $this->assertEquals('
' . get_string('partiallycorrect', 'question') . '
' . + '
' . + get_string('gradingdetails', 'qbehaviour_adaptive', $mark) . ' ' . + get_string('gradingdetailsadjustment', 'qbehaviour_adaptive', $mark) . '
', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$gradedpartial, 1, 0.8, 1.0, 0.1, 0.3, false), $this->options)); + } + + public function test_correct_third_try_if_we_dont_increase_penalties_for_wrong() { + $mark = array('cur' => '0.80', 'raw' => '1.00', 'max' => '1.00'); + $this->assertEquals('
' . get_string('partiallycorrect', 'question') . '
' . + '
' . + get_string('gradingdetails', 'qbehaviour_adaptive', $mark) . ' ' . + get_string('gradingdetailsadjustment', 'qbehaviour_adaptive', $mark) . '
', + $this->renderer->render_adaptive_marks(new qbehaviour_adaptive_mark_details( + question_state::$gradedpartial, 1, 0.8, 1.0, 0, 0.2, false), $this->options)); + } +} diff --git a/question/behaviour/adaptivenopenalty/renderer.php b/question/behaviour/adaptivenopenalty/renderer.php index 8b1e738cf36..34d3ae184f8 100644 --- a/question/behaviour/adaptivenopenalty/renderer.php +++ b/question/behaviour/adaptivenopenalty/renderer.php @@ -38,8 +38,7 @@ require_once(dirname(__FILE__) . '/../adaptive/renderer.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class qbehaviour_adaptivenopenalty_renderer extends qbehaviour_adaptive_renderer { - protected function penalty_info(question_attempt $qa, $mark, - question_display_options $options) { + protected function penalty_info(qbehaviour_adaptive_mark_details $details, question_display_options $options) { return ''; } protected function disregarded_info() { From c0a912e5acbd0d25118b9c8a7d8cc5da5a237b65 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Mon, 16 Jul 2012 14:30:12 +0100 Subject: [PATCH 035/106] MDL-34226 multichoice qtype: correct is_complete_response for multianswer The multianswer qtype uses the multi-choice one, and the way it does its responses array breaks an assumption that multi-choice was making. --- question/type/multichoice/question.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/question/type/multichoice/question.php b/question/type/multichoice/question.php index f31ceb6e443..afca6a47740 100644 --- a/question/type/multichoice/question.php +++ b/question/type/multichoice/question.php @@ -199,7 +199,7 @@ class qtype_multichoice_single_question extends qtype_multichoice_base { } public function is_complete_response(array $response) { - return array_key_exists('answer', $response); + return array_key_exists('answer', $response) && $response['answer'] !== ''; } public function is_gradable_response(array $response) { From be1d8ed194f199c3afe3ec8d3e8718295932b5c9 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Mon, 16 Jul 2012 14:32:25 +0100 Subject: [PATCH 036/106] MDL-34226 multianswer qtype: basic unit test. This verifies the previous fix, and gets rid of a rather embarassing TODO. --- question/type/multianswer/tests/helper.php | 75 ++++++++++++++++++- .../multianswer/tests/walkthrough_test.php | 57 +++++--------- 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/question/type/multianswer/tests/helper.php b/question/type/multianswer/tests/helper.php index 90f78efb3f7..75a3d7dcf47 100644 --- a/question/type/multianswer/tests/helper.php +++ b/question/type/multianswer/tests/helper.php @@ -38,7 +38,7 @@ require_once($CFG->dirroot . '/question/type/multianswer/question.php'); */ class qtype_multianswer_test_helper extends question_test_helper { public function get_test_questions() { - return array('twosubq'); + return array('twosubq', 'fourmc'); } /** @@ -54,6 +54,14 @@ class qtype_multianswer_test_helper extends question_test_helper { 'Complete this opening line of verse: "The {#1} and the {#2} went to sea".'; $q->generalfeedback = 'General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: ' . '"The owl and the pussycat went to sea'; + $q->qtype = question_bank::get_qtype('multianswer'); + + $q->textfragments = array( + 'Complete this opening line of verse: "The ', + ' and the ', + ' went to sea".', + ); + $q->places = array('1' => '1', '2' => '2'); // Shortanswer subquestion. question_bank::load_question_definition_classes('shortanswer'); @@ -214,4 +222,69 @@ class qtype_multianswer_test_helper extends question_test_helper { return $formdata; } + + /** + * Makes a multianswer question about completing two blanks in some text. + * @return qtype_multianswer_question + */ + public function make_multianswer_question_fourmc() { + question_bank::load_question_definition_classes('multianswer'); + $q = new qtype_multianswer_question(); + test_question_maker::initialise_a_question($q); + $q->name = 'Multianswer four multi-choice'; + $q->questiontext = '

Match the following cities with the correct state:

+
    +
  • San Francisco: {#1}
  • +
  • Tucson: {#2}
  • +
  • Los Angeles: {#3}
  • +
  • Phoenix: {#4}
  • +
'; + $q->questiontextformat = FORMAT_HTML; + $q->generalfeedback = ''; + $q->qtype = question_bank::get_qtype('multianswer'); + + $q->textfragments = array('

Match the following cities with the correct state:

+
    +
  • San Francisco: ', '
  • +
  • Tucson: ', '
  • +
  • Los Angeles: ', '
  • +
  • Phoenix: ', '
  • +
'); + $q->places = array('1' => '1', '2' => '2', '3' => '3', '4' => '4'); + + $subqdata = array( + 1 => array('qt' => '{1:MULTICHOICE:=California#OK~Arizona#Wrong}', 'California' => 'OK', 'Arizona' => 'Wrong'), + 2 => array('qt' => '{1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}', 'California' => 'Wrong', 'Arizona' => 'OK'), + 3 => array('qt' => '{1:MULTICHOICE:=California#OK~Arizona#Wrong}', 'California' => 'OK', 'Arizona' => 'Wrong'), + 4 => array('qt' => '{1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}', 'California' => 'Wrong', 'Arizona' => 'OK'), + ); + + foreach ($subqdata as $i => $data) { + // Multiple-choice subquestion. + question_bank::load_question_definition_classes('multichoice'); + $mc = new qtype_multichoice_single_question(); + test_question_maker::initialise_a_question($mc); + $mc->name = 'Multianswer four multi-choice'; + $mc->questiontext = $data['qt']; + $mc->questiontextformat = FORMAT_HTML; + $mc->generalfeedback = ''; + $mc->generalfeedbackformat = FORMAT_HTML; + + $mc->shuffleanswers = 0; // TODO this is a cheat to make the unit tests easier to write. + // In reality, multianswer questions always shuffle. + $mc->answernumbering = 'none'; + $mc->layout = qtype_multichoice_base::LAYOUT_DROPDOWN; + + $mc->answers = array( + 10 * $i => new question_answer(13, 'California', $data['California'] == 'OK', $data['California'], FORMAT_HTML), + 10 * $i + 1 => new question_answer(14, 'Arizona', $data['Arizona'] == 'OK', $data['Arizona'], FORMAT_HTML), + ); + $mc->qtype = question_bank::get_qtype('multichoice'); + $mc->maxmark = 1; + + $q->subquestions[$i] = $mc; + } + + return $q; + } } diff --git a/question/type/multianswer/tests/walkthrough_test.php b/question/type/multianswer/tests/walkthrough_test.php index 65dff591520..19af3c7564b 100644 --- a/question/type/multianswer/tests/walkthrough_test.php +++ b/question/type/multianswer/tests/walkthrough_test.php @@ -37,70 +37,53 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_base { - public function test_interactive() { - return; // TODO + public function test_deferred_feedback() { // Create a gapselect question. - $q = test_question_maker::make_question('calculated'); - $q->hints = array( - new question_hint(1, 'This is the first hint.', FORMAT_HTML), - new question_hint(2, 'This is the second hint.', FORMAT_HTML), - ); - $this->start_attempt_at_question($q, 'interactive', 3); - $values = $q->vs->get_values(); + $q = test_question_maker::make_question('multianswer', 'fourmc'); + $this->start_attempt_at_question($q, 'deferredfeedback', 4); // Check the initial state. $this->check_current_state(question_state::$todo); $this->check_current_mark(null); $this->check_current_output( $this->get_contains_marked_out_of_summary(), - $this->get_contains_submit_button_expectation(true), $this->get_does_not_contain_feedback_expectation(), - $this->get_does_not_contain_validation_error_expectation(), - $this->get_does_not_contain_try_again_button_expectation(), - $this->get_no_hint_visible_expectation()); + $this->get_does_not_contain_validation_error_expectation()); - // Submit blank. - $this->process_submission(array('-submit' => 1, 'answer' => '')); + // Save in incomplete answer. + $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '', + 'sub3_answer' => '', 'sub4_answer' => '')); // Verify. $this->check_current_state(question_state::$invalid); $this->check_current_mark(null); $this->check_current_output( $this->get_contains_marked_out_of_summary(), - $this->get_contains_submit_button_expectation(true), $this->get_does_not_contain_feedback_expectation(), - $this->get_contains_validation_error_expectation(), - $this->get_does_not_contain_try_again_button_expectation(), - $this->get_no_hint_visible_expectation()); + $this->get_does_not_contain_validation_error_expectation()); // TODO, really, it should. See MDL-32049. - // Sumit something that does not look like a number. - $this->process_submission(array('-submit' => 1, 'answer' => 'newt')); + // Save a partially correct answer. + $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1', + 'sub3_answer' => '1', 'sub4_answer' => '1')); // Verify. - $this->check_current_state(question_state::$invalid); + $this->check_current_state(question_state::$complete); $this->check_current_mark(null); $this->check_current_output( $this->get_contains_marked_out_of_summary(), - $this->get_contains_submit_button_expectation(true), $this->get_does_not_contain_feedback_expectation(), - $this->get_contains_validation_error_expectation(), - new question_pattern_expectation('/' . - preg_quote(get_string('invalidnumber', 'qtype_numerical') . '/')), - $this->get_does_not_contain_try_again_button_expectation(), - $this->get_no_hint_visible_expectation()); + $this->get_does_not_contain_validation_error_expectation()); - // Now get it right. - $this->process_submission(array('-submit' => 1, 'answer' => $values['a'] + $values['b'])); + // Now submit all and finish. + $this->process_submission(array('-finish' => 1)); // Verify. - $this->check_current_state(question_state::$gradedright); - $this->check_current_mark(3); + $this->check_current_state(question_state::$gradedpartial); + $this->check_current_mark(2); $this->check_current_output( - $this->get_contains_mark_summary(3), - $this->get_contains_submit_button_expectation(false), - $this->get_contains_correct_expectation(), - $this->get_does_not_contain_validation_error_expectation(), - $this->get_no_hint_visible_expectation()); + $this->get_contains_mark_summary(2), + $this->get_contains_partcorrect_expectation(), + $this->get_does_not_contain_validation_error_expectation()); } } From dd7aa58386ed842691c061e8c50dcc8987b86685 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 17 Jul 2012 17:32:56 +0100 Subject: [PATCH 037/106] MDL-34251 question engine: possible infinite loop loading usages In the case where either a question_attempt had not steps, or a question_usage had not question_attempts, the load_from_records methods could get stuck in an infinite loop. This fix ensures that does not happen, with unit tests to verify it. At the same time, I noticed an error in the existing tests, which this patch fixes. --- question/engine/questionattempt.php | 9 +++ question/engine/questionusage.php | 8 +++ .../tests/questionusagebyactivity_test.php | 68 +++++++++++++++++-- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php index 54c4d9f8390..1be7df264b0 100644 --- a/question/engine/questionattempt.php +++ b/question/engine/questionattempt.php @@ -1213,6 +1213,15 @@ class question_attempt { $qa->behaviour = question_engine::make_behaviour( $record->behaviour, $qa, $preferredbehaviour); + // If attemptstepid is null (which should not happen, but has happened + // due to corrupt data, see MDL-34251) then the current pointer in $records + // will not be advanced in the while loop below, and we get stuck in an + // infinite loop, since this method is supposed to always consume at + // least one record. Therefore, in this case, advance the record here. + if (is_null($record->attemptstepid)) { + $records->next(); + } + $i = 0; while ($record && $record->questionattemptid == $questionattemptid && !is_null($record->attemptstepid)) { $qa->steps[$i] = question_attempt_step::load_from_records($records, $record->attemptstepid); diff --git a/question/engine/questionusage.php b/question/engine/questionusage.php index 8d7ffa92096..f9470c0060e 100644 --- a/question/engine/questionusage.php +++ b/question/engine/questionusage.php @@ -714,6 +714,14 @@ class question_usage_by_activity { $quba->observer = new question_engine_unit_of_work($quba); + // If slot is null then the current pointer in $records will not be + // advanced in the while loop below, and we get stuck in an infinite loop, + // since this method is supposed to always consume at least one record. + // Therefore, in this case, advance the record here. + if (is_null($record->slot)) { + $records->next(); + } + while ($record && $record->qubaid == $qubaid && !is_null($record->slot)) { $quba->questionattempts[$record->slot] = question_attempt::load_from_records($records, diff --git a/question/engine/tests/questionusagebyactivity_test.php b/question/engine/tests/questionusagebyactivity_test.php index 73ff8b30de8..71434ee5270 100644 --- a/question/engine/tests/questionusagebyactivity_test.php +++ b/question/engine/tests/questionusagebyactivity_test.php @@ -169,16 +169,17 @@ class question_usage_by_activity_test extends advanced_testcase { */ class question_usage_db_test extends data_loading_method_test_base { public function test_load() { + $scid = context_system::instance()->id; $records = new question_test_recordset(array( array('qubaid', 'contextid', 'component', 'preferredbehaviour', - 'questionattemptid', 'contextid', 'questionusageid', 'slot', + 'questionattemptid', 'questionusageid', 'slot', 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', 'attemptstepid', 'sequencenumber', 'state', 'fraction', 'timecreated', 'userid', 'name', 'value'), - array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), - array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo', null, 1256233705, 1, 'answer', '1'), - array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 2, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'), + array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), + array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo', null, 1256233705, 1, 'answer', '1'), + array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 2, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'), )); $question = test_question_maker::make_question('truefalse', 'true'); @@ -221,4 +222,63 @@ class question_usage_db_test extends data_loading_method_test_base { $this->assertEquals(1, $step->get_user_id()); $this->assertEquals(array('-finish' => '1'), $step->get_all_data()); } + + public function test_load_data_no_steps() { + // The code had a bug where if one question_attempt had no steps, + // load_from_records got stuck in an infinite loop. This test is to + // verify that no longer happens. + $scid = context_system::instance()->id; + $records = new question_test_recordset(array( + array('qubaid', 'contextid', 'component', 'preferredbehaviour', + 'questionattemptid', 'questionusageid', 'slot', + 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', + 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', + 'attemptstepid', 'sequencenumber', 'state', 'fraction', + 'timecreated', 'userid', 'name', 'value'), + array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null), + array(1, $scid, 'unit_test', 'interactive', 2, 1, 2, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null), + array(1, $scid, 'unit_test', 'interactive', 3, 1, 3, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null), + )); + + question_bank::start_unit_test(); + $quba = question_usage_by_activity::load_from_records($records, 1); + question_bank::end_unit_test(); + + $this->assertEquals('unit_test', $quba->get_owning_component()); + $this->assertEquals(1, $quba->get_id()); + $this->assertInstanceOf('question_engine_unit_of_work', $quba->get_observer()); + $this->assertEquals('interactive', $quba->get_preferred_behaviour()); + + $this->assertEquals(array(1, 2, 3), $quba->get_slots()); + + $qa = $quba->get_question_attempt(1); + $this->assertEquals(0, $qa->get_num_steps()); + } + + public function test_load_data_no_qas() { + // The code had a bug where if a question_usage had no question_attempts, + // load_from_records got stuck in an infinite loop. This test is to + // verify that no longer happens. + $scid = context_system::instance()->id; + $records = new question_test_recordset(array( + array('qubaid', 'contextid', 'component', 'preferredbehaviour', + 'questionattemptid', 'questionusageid', 'slot', + 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', + 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', + 'attemptstepid', 'sequencenumber', 'state', 'fraction', + 'timecreated', 'userid', 'name', 'value'), + array(1, $scid, 'unit_test', 'interactive', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), + )); + + question_bank::start_unit_test(); + $quba = question_usage_by_activity::load_from_records($records, 1); + question_bank::end_unit_test(); + + $this->assertEquals('unit_test', $quba->get_owning_component()); + $this->assertEquals(1, $quba->get_id()); + $this->assertInstanceOf('question_engine_unit_of_work', $quba->get_observer()); + $this->assertEquals('interactive', $quba->get_preferred_behaviour()); + + $this->assertEquals(array(), $quba->get_slots()); + } } From 7326b7e24754a8f4ba7ec06ce01502aa6d3228cc Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 17 Jul 2012 16:18:22 +0100 Subject: [PATCH 038/106] MDL-34379 quiz reports: timetaken 'open' for never submitted attempts --- mod/quiz/report/attemptsreport_table.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/mod/quiz/report/attemptsreport_table.php b/mod/quiz/report/attemptsreport_table.php index 03f8959e4df..4334256eb18 100644 --- a/mod/quiz/report/attemptsreport_table.php +++ b/mod/quiz/report/attemptsreport_table.php @@ -189,8 +189,6 @@ abstract class quiz_attempts_report_table extends table_sql { public function col_duration($attempt) { if ($attempt->timefinish) { return format_time($attempt->timefinish - $attempt->timestart); - } else if ($attempt->timestart) { - return get_string('unfinished', 'quiz'); } else { return '-'; } From c33d5278337b111ccc86dfa13f2663800750a0d3 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Tue, 17 Jul 2012 16:30:33 +0100 Subject: [PATCH 039/106] MDL-34351 quiz cron: one broken overdue attempt should not kill cron It seems that sometimes trying to process an overdue quiz attempt can throw an exception. In that case, we need to catch it and report it nicely, and then carry on processing the rest of the attempts, rather than just killing the whole of cron processing. Also, there may be garbage quiz attempts where the associated quiz or course has been deleted. Skip those too. --- mod/quiz/cronlib.php | 49 ++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/mod/quiz/cronlib.php b/mod/quiz/cronlib.php index 111419c1f4b..7913b63cf58 100644 --- a/mod/quiz/cronlib.php +++ b/mod/quiz/cronlib.php @@ -57,27 +57,36 @@ class mod_quiz_overdue_attempt_updater { $count = 0; $quizcount = 0; foreach ($attemptstoprocess as $attempt) { - // If we have moved on to a different quiz, fetch the new data. - if (!$quiz || $attempt->quiz != $quiz->id) { - $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST); - $cm = get_coursemodule_from_instance('quiz', $attempt->quiz); - $quizcount += 1; + try { + + // If we have moved on to a different quiz, fetch the new data. + if (!$quiz || $attempt->quiz != $quiz->id) { + $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST); + $cm = get_coursemodule_from_instance('quiz', $attempt->quiz); + $quizcount += 1; + } + + // If we have moved on to a different course, fetch the new data. + if (!$course || $course->id != $quiz->course) { + $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST); + } + + // Make a specialised version of the quiz settings, with the relevant overrides. + $quizforuser = clone($quiz); + $quizforuser->timeclose = $attempt->usertimeclose; + $quizforuser->timelimit = $attempt->usertimelimit; + + // Trigger any transitions that are required. + $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course); + $attemptobj->handle_if_time_expired($timenow, false); + $count += 1; + + } catch (moodle_exception $e) { + // If an error occurs while processing one attempt, don't let that kill cron. + mtrace("Error while processing attempt {$attempt->id} at {$attempt->quiz} quiz:"); + mtrace($e->getMessage()); + mtrace($e->getTraceAsString()); } - - // If we have moved on to a different course, fetch the new data. - if (!$course || $course->id != $quiz->course) { - $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST); - } - - // Make a specialised version of the quiz settings, with the relevant overrides. - $quizforuser = clone($quiz); - $quizforuser->timeclose = $attempt->usertimeclose; - $quizforuser->timelimit = $attempt->usertimelimit; - - // Trigger any transitions that are required. - $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course); - $attemptobj->handle_if_time_expired($timenow, false); - $count += 1; } $attemptstoprocess->close(); From 6aa3aabe95a1e97b24be6b7f941f70f1013db8ad Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 17 Jul 2012 16:42:22 +0800 Subject: [PATCH 040/106] MDL-33560 Enrol: Enrol password can be unmasked --- enrol/self/locallib.php | 4 ++-- lib/form/yui/passwordunmask/passwordunmask.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/enrol/self/locallib.php b/enrol/self/locallib.php index 86adfbf819d..a189e7d4066 100644 --- a/enrol/self/locallib.php +++ b/enrol/self/locallib.php @@ -67,7 +67,7 @@ class enrol_self_enrol_form extends moodleform { if ($instance->password) { //change the id of self enrolment key input as there can be multiple self enrolment methods $mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_self'), - array('id' => $instance->id."_enrolpassword")); + array('id' => 'enrolpassword_'.$instance->id)); } else { $mform->addElement('static', 'nokey', '', get_string('nopassword', 'enrol_self')); } @@ -127,4 +127,4 @@ class enrol_self_enrol_form extends moodleform { return $errors; } -} \ No newline at end of file +} diff --git a/lib/form/yui/passwordunmask/passwordunmask.js b/lib/form/yui/passwordunmask/passwordunmask.js index 2b98922d47c..dfe4de4b472 100644 --- a/lib/form/yui/passwordunmask/passwordunmask.js +++ b/lib/form/yui/passwordunmask/passwordunmask.js @@ -36,4 +36,4 @@ YUI.add('moodle-form-passwordunmask', function(Y) { M.form.passwordunmask = function(params) { return new PASSWORDUNMASK(params); } -}, '@VERSION@', {requires:['base', 'node']}); \ No newline at end of file +}, '@VERSION@', {requires:['base', 'node']}); From b1c669a711f2181d5d036d5d9eb0b34b4c04d04d Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Mon, 9 Jul 2012 21:39:34 +0100 Subject: [PATCH 041/106] MDL-34221 Filepicker - disableIf now prevents drag and drop upload --- lib/form/dndupload.js | 14 ++++++++++++++ lib/form/form.js | 4 ++++ theme/base/style/filemanager.css | 2 ++ 3 files changed, 20 insertions(+) diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js index 53018b9f08e..0cdeeee21fd 100644 --- a/lib/form/dndupload.js +++ b/lib/form/dndupload.js @@ -165,11 +165,22 @@ M.form_dndupload.init = function(Y, options) { this.Y.on('dragleave', this.drag_leave_page, 'body', this); }, + /** + * Check if the filemanager / filepicker is disabled + * @return bool - true if disabled + */ + is_disabled: function() { + return this.container.hasClass('disabled'); + }, + /** * Show the 'drop files here' message when file(s) are dragged * onto the page */ drag_enter_page: function(e) { + if (this.is_disabled()) { + return false; + } if (!this.has_files(e)) { return false; } @@ -210,6 +221,9 @@ M.form_dndupload.init = function(Y, options) { * @return boolean true if a valid file drag event */ check_drag: function(e) { + if (this.is_disabled()) { + return false; + } if (!this.has_files(e)) { return false; } diff --git a/lib/form/form.js b/lib/form/form.js index 938fab6be66..2dd75f498f0 100644 --- a/lib/form/form.js +++ b/lib/form/form.js @@ -211,10 +211,14 @@ M.form.initFormDependencies = function(Y, formid, dependencies) { if (this.getAttribute('class') == 'filepickerhidden'){ var pickerbuttons = form.elementsByName(name + 'choose'); pickerbuttons.each(function(){ + var clientid = this.get('id').split('-')[2]; + var filepicker = Y.one('#file_info_'+clientid); if (disabled){ this.setAttribute('disabled','disabled'); + filepicker.addClass('disabled'); } else { this.removeAttribute('disabled'); + filepicker.removeClass('disabled'); } }); } diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css index 5fbacc3599f..99cdb994077 100644 --- a/theme/base/style/filemanager.css +++ b/theme/base/style/filemanager.css @@ -326,6 +326,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;} /* * Drag and drop support (File Manager only) */ +.filepicker-filelist.disabled {background-color:#ddd;} +.filepicker-filelist.disabled .filepicker-filename {display:none;} .filepicker-filelist .filepicker-container, .filemanager.fm-noitems .fm-empty-container {display:block;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #BBBBBB;padding-top:85px;text-align:center;z-index: 3000;} .filepicker-filelist .dndupload-target, From c81f332876e79ab71db930ced89fdd7732554f30 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 13 Jul 2012 16:02:21 +0800 Subject: [PATCH 042/106] MDL-34221 disabledIf support for filemanager and filepicker elements --- lib/form/dndupload.js | 2 +- lib/form/filemanager.js | 21 +++++++++++++++++++-- lib/form/filepicker.js | 4 +++- lib/form/form.js | 22 ++++++++-------------- lib/outputrenderers.php | 2 +- theme/base/style/filemanager.css | 12 +++++++++--- 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js index 0cdeeee21fd..bbadd5c03f6 100644 --- a/lib/form/dndupload.js +++ b/lib/form/dndupload.js @@ -170,7 +170,7 @@ M.form_dndupload.init = function(Y, options) { * @return bool - true if disabled */ is_disabled: function() { - return this.container.hasClass('disabled'); + return (this.container.ancestor('.fitem.disabled') != null); }, /** diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js index 164c6834a4b..cbd528a71d5 100644 --- a/lib/form/filemanager.js +++ b/lib/form/filemanager.js @@ -255,6 +255,9 @@ M.form_filemanager.init = function(Y, options) { this.msg_dlg_node.one('.fp-msg-text').setContent(msg); this.msg_dlg.show(); }, + is_disabled: function() { + return this.filemanager.ancestor('.fitem.disabled') != null; + }, setup_buttons: function() { var button_download = this.filemanager.one('.fp-btn-download'); var button_create = this.filemanager.one('.fp-btn-mkdir'); @@ -272,6 +275,9 @@ M.form_filemanager.init = function(Y, options) { if (this.options.subdirs) { button_create.on('click',function(e) { e.preventDefault(); + if (this.is_disabled()) { + return; + } var scope = this; // a function used to perform an ajax request var perform_action = function(e) { @@ -325,6 +331,9 @@ M.form_filemanager.init = function(Y, options) { // setup 'download this folder' button button_download.on('click',function(e) { e.preventDefault(); + if (this.is_disabled()) { + return; + } var scope = this; // perform downloaddir ajax request this.request({ @@ -351,7 +360,7 @@ M.form_filemanager.init = function(Y, options) { on('click', function(e) { e.preventDefault(); var viewbar = this.filemanager.one('.fp-viewbar') - if (!viewbar || !viewbar.hasClass('disabled')) { + if (!this.is_disabled() && (!viewbar || !viewbar.hasClass('disabled'))) { this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked') if (e.currentTarget.hasClass('fp-vb-tree')) { this.viewmode = 2; @@ -369,6 +378,9 @@ M.form_filemanager.init = function(Y, options) { show_filepicker: function (e) { // if maxfiles == -1, the no limit e.preventDefault(); + if (this.is_disabled()) { + return; + } var options = this.filepicker_options; options.formcallback = this.filepicker_callback; // XXX: magic here, to let filepicker use filemanager scope @@ -400,7 +412,9 @@ M.form_filemanager.init = function(Y, options) { el.one('.fp-path-folder-name').setContent(p[i].name). on('click', function(e, path) { e.preventDefault(); - this.refresh(path); + if (!this.is_disabled()) { + this.refresh(path); + } }, this, p[i].path); } this.pathbar.removeClass('empty'); @@ -873,6 +887,9 @@ M.form_filemanager.init = function(Y, options) { return node.filepath; }, select_file: function(node) { + if (this.is_disabled()) { + return; + } var selectnode = this.selectnode; selectnode.removeClass('loading').removeClass('fp-folder'). removeClass('fp-file').removeClass('fp-zip').removeClass('fp-cansetmain'); diff --git a/lib/form/filepicker.js b/lib/form/filepicker.js index e372a23c086..b2811a25dbc 100644 --- a/lib/form/filepicker.js +++ b/lib/form/filepicker.js @@ -32,7 +32,9 @@ M.form_filepicker.init = function(Y, options) { } Y.on('click', function(e, client_id) { e.preventDefault(); - M.core_filepicker.instances[client_id].show(); + if (this.ancestor('.fitem.disabled') == null) { + M.core_filepicker.instances[client_id].show(); + } }, '#filepicker-button-'+options.client_id, null, options.client_id); var item = document.getElementById('nonjs-filepicker-'+options.client_id); diff --git a/lib/form/form.js b/lib/form/form.js index 2dd75f498f0..b49d76a0437 100644 --- a/lib/form/form.js +++ b/lib/form/form.js @@ -207,20 +207,14 @@ M.form.initFormDependencies = function(Y, formid, dependencies) { this.removeAttribute('disabled'); } - // Extra code to disable a filepicker - if (this.getAttribute('class') == 'filepickerhidden'){ - var pickerbuttons = form.elementsByName(name + 'choose'); - pickerbuttons.each(function(){ - var clientid = this.get('id').split('-')[2]; - var filepicker = Y.one('#file_info_'+clientid); - if (disabled){ - this.setAttribute('disabled','disabled'); - filepicker.addClass('disabled'); - } else { - this.removeAttribute('disabled'); - filepicker.removeClass('disabled'); - } - }); + // Extra code to disable filepicker or filemanager form elements + var fitem = this.ancestor('.fitem'); + if (fitem && (fitem.hasClass('fitem_ffilemanager') || fitem.hasClass('fitem_ffilepicker'))) { + if (disabled){ + fitem.addClass('disabled'); + } else { + fitem.removeClass('disabled'); + } } }) }, diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index b2d0e491005..e800b8f21e2 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -2050,7 +2050,7 @@ $icon_progress