Merge branch 'MDL-68011-master' of https://github.com/mihailges/moodle

This commit is contained in:
Jun Pataleta 2022-07-19 20:52:14 +08:00
commit 155ef8aece
12 changed files with 62 additions and 248 deletions

View File

@ -61,63 +61,6 @@ class content_item_readonly_repository implements content_item_readonly_reposito
return $help;
}
/**
* Create a content_item object based on legacy data returned from the get_shortcuts hook implementations.
*
* @param \stdClass $item the stdClass of legacy data.
* @return content_item a content item object.
*/
private function content_item_from_legacy_data(\stdClass $item): content_item {
global $OUTPUT;
// Make sure the legacy data results in a content_item with id = 0.
// Even with an id, we can't uniquely identify the item, because we can't guarantee what component it came from.
// An id of -1, signifies this.
$item->id = -1;
// If the module provides the helplink property, append it to the help text to match the look and feel
// of the default course modules.
if (isset($item->help) && isset($item->helplink)) {
$linktext = get_string('morehelp');
$item->help .= \html_writer::tag('div',
$OUTPUT->doc_link($item->helplink, $linktext, true), ['class' => 'helpdoclink']);
}
if (is_string($item->title)) {
$item->title = new string_title($item->title);
} else if ($item->title instanceof \lang_string) {
$item->title = new lang_string_title($item->title->get_identifier(), $item->title->get_component());
}
// Legacy items had names which are in one of 2 forms:
// modname, i.e. 'assign' or
// modname:link, i.e. lti:http://etc...
// We need to grab the module name out to create the componentname.
$modname = (strpos($item->name, ':') !== false) ? explode(':', $item->name)[0] : $item->name;
$purpose = plugin_supports('mod', $modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER);
return new content_item($item->id, $item->name, $item->title, $item->link, $item->icon, $item->help ?? '',
$item->archetype, 'mod_' . $modname, $purpose);
}
/**
* Create a stdClass type object based on a content_item instance.
*
* @param content_item $contentitem
* @return \stdClass the legacy data.
*/
private function content_item_to_legacy_data(content_item $contentitem): \stdClass {
$item = new \stdClass();
$item->id = $contentitem->get_id();
$item->name = $contentitem->get_name();
$item->title = $contentitem->get_title();
$item->link = $contentitem->get_link();
$item->icon = $contentitem->get_icon();
$item->help = $contentitem->get_help();
$item->archetype = $contentitem->get_archetype();
$item->componentname = $contentitem->get_component_name();
return $item;
}
/**
* Helper to get the contentitems from all subplugin hooks for a given module plugin.
*
@ -165,20 +108,6 @@ class content_item_readonly_repository implements content_item_readonly_reposito
return $contentitems;
}
/**
* Helper to make sure any legacy items have certain properties, which, if missing are inherited from the parent module item.
*
* @param \stdClass $legacyitem the legacy information, a stdClass coming from get_shortcuts() hook.
* @param content_item $modulecontentitem The module's content item information, to inherit if needed.
* @return \stdClass the updated legacy item stdClass
*/
private function legacy_item_inherit_missing(\stdClass $legacyitem, content_item $modulecontentitem): \stdClass {
// Fall back to the plugin parent value if the subtype didn't provide anything.
$legacyitem->archetype = $legacyitem->archetype ?? $modulecontentitem->get_archetype();
$legacyitem->icon = $legacyitem->icon ?? $modulecontentitem->get_icon();
return $legacyitem;
}
/**
* Find all the available content items, not restricted to course or user.
*
@ -254,9 +183,6 @@ class content_item_readonly_repository implements content_item_readonly_reposito
$modules = $DB->get_records('modules', ['visible' => 1]);
$return = [];
// A moodle_url is expected and required by modules in their implementation of the hook 'get_shortcuts'.
$urlbase = new \moodle_url('/course/mod.php', ['id' => $course->id]);
// Now, generate the content_items.
foreach ($modules as $modid => $mod) {
// Exclude modules if the code doesn't exist.
@ -273,7 +199,7 @@ class content_item_readonly_repository implements content_item_readonly_reposito
$mod->id,
$mod->name,
new lang_string_title("modulename", $mod->name),
new \moodle_url($urlbase, ['add' => $mod->name]),
new \moodle_url('/course/mod.php', ['id' => $course->id, 'add' => $mod->name]),
$OUTPUT->pix_icon('monologo', '', $mod->name, ['class' => 'icon activityicon']),
$help,
$archetype,
@ -281,10 +207,6 @@ class content_item_readonly_repository implements content_item_readonly_reposito
$purpose,
);
// Legacy vs new hooks.
// If the new hook is found for a module plugin, use that path (calling mod plugins and their subplugins directly)
// If not, check the legacy hook. This won't provide us with enough information to identify items uniquely within their
// component (lti + lti source being an example), but we can still list these items.
$modcontentitemreference = clone($contentitem);
if (component_callback_exists('mod_' . $mod->name, 'get_course_content_items')) {
@ -301,37 +223,8 @@ class content_item_readonly_repository implements content_item_readonly_reposito
array_push($return, ...$subpluginitems);
}
} else if (component_callback_exists('mod_' . $mod->name, 'get_shortcuts')) {
// TODO: MDL-68011 this block needs to be removed in 4.1.
debugging('The callback get_shortcuts has been deprecated. Please use get_course_content_items and
get_all_content_items instead. Some features of the activity chooser, such as favourites and recommendations
are not supported when providing content items via the deprecated callback.');
// If get_shortcuts() callback is defined, the default module action is not added.
// It is a responsibility of the callback to add it to the return value unless it is not needed.
// The legacy hook, get_shortcuts, expects a stdClass representation of the core module content_item entry.
$modcontentitemreference = $this->content_item_to_legacy_data($contentitem);
$legacyitems = component_callback($mod->name, 'get_shortcuts', [$modcontentitemreference], null);
if (!is_null($legacyitems)) {
foreach ($legacyitems as $legacyitem) {
$legacyitem = $this->legacy_item_inherit_missing($legacyitem, $contentitem);
// All items must have different links, use them as a key in the return array.
// If plugin returned the only one item with the same link as default item - keep $modname,
// otherwise append the link url to the module name.
$legacyitem->name = (count($legacyitems) == 1 &&
$legacyitem->link->out() === $contentitem->get_link()->out()) ? $mod->name : $mod->name . ':' .
$legacyitem->link;
$plugincontentitem = $this->content_item_from_legacy_data($legacyitem);
$return[] = $plugincontentitem;
}
}
} else {
// Neither callback was found, so just use the default module content item.
// Callback was not found, so just use the default module content item.
$return[] = $contentitem;
}
}

View File

@ -378,7 +378,6 @@ class format_singleactivity extends core_courseformat\base {
/**
* Checks if the activity type has multiple items in the activity chooser.
* This may happen as a result of defining callback modulename_get_shortcuts().
*
* @return bool|null (null if the check is not possible)
*/

View File

@ -134,17 +134,10 @@ class core_course_renderer extends plugin_renderer_base {
}
/**
* Build the HTML for the module chooser javascript popup
*
* @param array $modules A set of modules as returned form @see
* get_module_metadata
* @param object $course The course that will be displayed
* @return string The composed HTML for the module
* @deprecated since 3.9
*/
public function course_modchooser($modules, $course) {
debugging('course_modchooser() is deprecated. Please use course_activitychooser() instead.', DEBUG_DEVELOPER);
return $this->course_activitychooser($course->id);
public function course_modchooser() {
throw new coding_exception('course_modchooser() can not be used anymore, please use course_activitychooser() instead.');
}
/**

View File

@ -1,6 +1,10 @@
This files describes API changes in /course/*,
information provided here is intended especially for developers.
=== 4.1 ===
* The function course_modchooser() has been finally deprecated and can not be used anymore. Please use
course_activitychooser() instead.
=== 4.0 ===
* All activity icons have been replaced with black monochrome icons. The background
colour for these icons is defined using a new 'FEATURE_MOD_PURPOSE' support variable in the module lib.php file

View File

@ -2770,102 +2770,11 @@ function report_insights_context_insights(\context $context) {
}
/**
* Retrieve all metadata for the requested modules
*
* @deprecated since 3.9.
* @param object $course The Course
* @param array $modnames An array containing the list of modules and their
* names
* @param int $sectionreturn The section to return to
* @return array A list of stdClass objects containing metadata about each
* module
* @deprecated since 3.9
*/
function get_module_metadata($course, $modnames, $sectionreturn = null) {
global $OUTPUT;
debugging('get_module_metadata is deprecated. Please use \core_course\local\service\content_item_service instead.');
// get_module_metadata will be called once per section on the page and courses may show
// different modules to one another
static $modlist = array();
if (!isset($modlist[$course->id])) {
$modlist[$course->id] = array();
}
$return = array();
$urlbase = new moodle_url('/course/mod.php', array('id' => $course->id, 'sesskey' => sesskey()));
if ($sectionreturn !== null) {
$urlbase->param('sr', $sectionreturn);
}
foreach($modnames as $modname => $modnamestr) {
if (!course_allowed_module($course, $modname)) {
continue;
}
if (isset($modlist[$course->id][$modname])) {
// This module is already cached
$return += $modlist[$course->id][$modname];
continue;
}
$modlist[$course->id][$modname] = array();
// Create an object for a default representation of this module type in the activity chooser. It will be used
// if module does not implement callback get_shortcuts() and it will also be passed to the callback if it exists.
$defaultmodule = new stdClass();
$defaultmodule->title = $modnamestr;
$defaultmodule->name = $modname;
$defaultmodule->link = new moodle_url($urlbase, array('add' => $modname));
$defaultmodule->icon = $OUTPUT->pix_icon('icon', '', $defaultmodule->name, array('class' => 'icon'));
$sm = get_string_manager();
if ($sm->string_exists('modulename_help', $modname)) {
$defaultmodule->help = get_string('modulename_help', $modname);
if ($sm->string_exists('modulename_link', $modname)) { // Link to further info in Moodle docs.
$link = get_string('modulename_link', $modname);
$linktext = get_string('morehelp');
$defaultmodule->help .= html_writer::tag('div',
$OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink'));
}
}
$defaultmodule->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
// Each module can implement callback modulename_get_shortcuts() in its lib.php and return the list
// of elements to be added to activity chooser.
$items = component_callback($modname, 'get_shortcuts', array($defaultmodule), null);
if ($items !== null) {
foreach ($items as $item) {
// Add all items to the return array. All items must have different links, use them as a key in the return array.
if (!isset($item->archetype)) {
$item->archetype = $defaultmodule->archetype;
}
if (!isset($item->icon)) {
$item->icon = $defaultmodule->icon;
}
// If plugin returned the only one item with the same link as default item - cache it as $modname,
// otherwise append the link url to the module name.
$item->name = (count($items) == 1 &&
$item->link->out() === $defaultmodule->link->out()) ? $modname : $modname . ':' . $item->link;
// If the module provides the helptext property, append it to the help text to match the look and feel
// of the default course modules.
if (isset($item->help) && isset($item->helplink)) {
$linktext = get_string('morehelp');
$item->help .= html_writer::tag('div',
$OUTPUT->doc_link($item->helplink, $linktext, true), array('class' => 'helpdoclink'));
}
$modlist[$course->id][$modname][$item->name] = $item;
}
$return += $modlist[$course->id][$modname];
// If get_shortcuts() callback is defined, the default module action is not added.
// It is a responsibility of the callback to add it to the return value unless it is not needed.
continue;
}
// The callback get_shortcuts() was not found, use the default item for the activity chooser.
$modlist[$course->id][$modname][$modname] = $defaultmodule;
$return[$modname] = $defaultmodule;
}
core_collator::asort_objects_by_property($return, 'title');
return $return;
function get_module_metadata() {
throw new coding_exception(
'get_module_metadata() has been removed. Please use \core_course\local\service\content_item_service instead.');
}
/**

View File

@ -37,6 +37,7 @@ information provided here is intended especially for developers.
* Added $CFG->proxylogunsafe and proxyfixunsafe to detect code which doesn't honor the proxy config
* Function admin_externalpage_setup() now has additional option 'nosearch' allowing to remove Site administration search form.
* The function print_error has been deprecated. Kindly use moodle_exception.
* The function get_module_metadata() has been finally deprecated and can not be used anymore.
=== 4.0 ===

32
mod/lti/deprecatedlib.php Normal file
View File

@ -0,0 +1,32 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* List of deprecated mod_lti functions.
*
* @package mod_lti
* @copyright 2022 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* @deprecated since 3.9
**/
function lti_get_shortcuts() {
throw new coding_exception(
'The callback get_shortcuts() is now removed. Please use get_course_content_items and get_all_content_items instead.'
);
}

View File

@ -225,39 +225,6 @@ function lti_delete_instance($id) {
}
/**
* Return aliases of this activity. LTI should have an alias for each configured tool type
* This is so you can add an external tool types directly to the activity chooser
*
* @deprecated since 3.9
* @todo MDL-68011 This is to be moved from here to deprecatedlib.php in Moodle 4.1
* @param stdClass $defaultitem default item that would be added to the activity chooser if this callback was not present.
* It has properties: archetype, name, title, help, icon, link
* @return array An array of aliases for this activity. Each element is an object with same list of properties as $defaultitem,
* plus an additional property, helplink.
* Properties title and link are required
**/
function lti_get_shortcuts($defaultitem) {
global $CFG, $COURSE;
require_once($CFG->dirroot.'/mod/lti/locallib.php');
$types = lti_get_configured_types($COURSE->id, $defaultitem->link->param('sr'));
if (has_capability('mod/lti:addmanualinstance', context_course::instance($COURSE->id))) {
$types[] = $defaultitem;
}
// Add items defined in ltisource plugins.
foreach (core_component::get_plugin_list('ltisource') as $pluginname => $dir) {
// LTISOURCE plugins can also implement callback get_shortcuts() to add items to the activity chooser.
// The return values are the same as of the 'mod' callbacks except that $defaultitem is only passed for reference and
// should not be added to the return value.
if ($moretypes = component_callback("ltisource_$pluginname", 'get_shortcuts', array($defaultitem))) {
$types = array_merge($types, $moretypes);
}
}
return $types;
}
/**
* Return the preconfigured tools which are configured for inclusion in the activity picker.
*

View File

@ -1,6 +1,10 @@
This files describes API changes in /mod/lti/source/* - LTI source plugins,
information provided here is intended especially for developers.
=== 4.1 ===
* The callback get_shortcuts() is now removed. Please use get_course_content_items and get_all_content_items instead.
=== 3.9 ===
* The callback get_shortcuts() is now deprecated. Please use get_course_content_items and get_all_content_items instead.

View File

@ -1,5 +1,9 @@
This files describes API changes in the lti code.
=== 4.1 ===
* The callback get_shortcuts() is now removed. Please use get_course_content_items and get_all_content_items instead.
=== 3.10 ===
* Select Content supports multiple, allowing a tool to return more than one link at a time.

View File

@ -1,6 +1,10 @@
This files describes API changes in /mod/* - activity modules,
information provided here is intended especially for developers.
=== 4.1 ===
* The callback get_shortcuts() is now removed. Please use get_course_content_items and get_all_content_items instead.
=== 4.0 ===
* A new API function introduced to handle custom completion logic. Refer to completion/upgrade.txt for additional information.
* Modules that extend the settings navigation via '_extend_settings_navigation()' should use the get_page() method from

View File

@ -1,6 +1,10 @@
This files describes API changes in /theme/* themes,
information provided here is intended especially for theme designer.
=== 4.1 ===
* The function core_course_renderer::course_modchooser() has been finally deprecated and can not be used anymore.
Please use core_course_renderer::course_activitychooser() instead.
=== 4.0 ===
* A new theme config 'removedprimarynavitems' allows a theme to customise primary navigation by specifying the list of items to remove.
* A new theme config 'usescourseindex' allows a theme to specify whether it implements and uses course index.