发布时间:2025-12-09 16:28:07 浏览次数:6
本文是我翻译并整理Moodle官方插件开发基础教程完成的,包含了每章的教学内容以及Quiz答案,一些我在学习中觉得翻译不妥的地方都使用了原文或进行了原文批注。由于我自己还在学习,所以仍在持续更新中。
整理不易,如有错误,还请包涵ww。
在Moodle模块化Moodle中的“M”代表“模块化”。大多数用户直接与之交互的特性都是通过独立的模块实现的,这些模块在Moodle中通常被称为插件。下载后,Moodle已经提供了许多标准插件。默认情况下,这些都是Moodle安装的一部分。甚至更多的插件可以作为附加插件安装。附加插件的官方存储库是Moodle plugins目录。那里的插件由独立的社区贡献者维护。在文件系统上,标准插件几乎占据了Moodle安装的一半。另一半由所谓的核心子系统组成。这些子系统提供了插件使用的核心api
插件类型Moodle中有许多插件类型,每一种都专注于特定的功能领域。每种插件类型都有自己的特性。了解各种插件类型的目的、可能性和限制是很重要的,这样你就可以选择最合适的类型来实现所要求的特性。所有给定类型的插件都安装在一个公共父目录中的单独目录中。例如,每个/blocks/*目录都是一个特定的插件,它们都是Block类型的一个插件不能有一种以上的类型。在Moodle中,每种插件类型都有其独特的安装位置。
活动模块是Moodle中必不可少的插件。它们代表着学习在课程中发生的活动。教师通过增加活动模块的实例(如测验、作业、论坛或书籍)来创建课程的主要内容例如,您当前正在阅读的这个特定文本是Book活动模块提供的HTML页面。有些模块,比如Books、url或Pages,在用户界面中被称为资源。活动模块通常以链接的形式显示在主课程页面的大纲中。
活动模块的共同特性
Blocks块是内容项目,可以添加到左,右或中心栏的任何页面在Moodle。块可能出现的区域由主题布局控制。块可以向用户显示有用的信息,如最近的课程活动、即将到来的日历事件或课程列表。
Blocks can also be used on the Dashboard.
块的常见特性
Moodle拥有强大的主题,可以通过使用HTML和CSS实现各种效果。主题定义了Moodle站点的外观和感觉
主题的共同特征
身份验证插件使用钩子(hooks)来增强或替换部分用户身份验证流。标准的身份验证方法包括根据内部存储的密码、LDAP或OAuth2提供商(如谷歌或Facebook)进行身份验证。
注册插件控制谁被注册到课程中,以及他们在那里扮演什么角色(因此也就有权限)。
课程中创建的注册插件可以有多个实例,通常每个实例都有自己的配置。
注册插件的共同特点
课程格式决定了课程主页的布局。教师可以在课程设置表中指定所选择的课程格式。
课程格式的常见功能
管理工具为各种站点管理和维护任务提供了有用的工具。管理员和管理人员通常可以通过站点管理树菜单访问它们。
不管它们的名字可能暗示什么,管理工具并不需要只被站点管理员使用。学习计划、数据隐私和用户参观(User tours)等功能实际上是由管理工具插件提供的,并为非管理用户(如学生)提供功能。
本地插件用于实现特定于站点或机构的功能。它们被设计成一种通用的插件类型,以一种干净和可维护的方式用于各种本地定制。通常情况下,它们甚至不应该被公开分发和分享本地插件也经常被用于那些不适合任何其他标准插件类型的特性。例如,整个Moodle plugins目录是作为一个安装在Moodle站点上的本地插件来实现的。
本地插件的特性
其他插件类型请参阅开发人员文档中的插件类型页面,以获得支持类型的广泛列表。其他常用的自定义插件类型包括
和其他类型。
每个Moodle插件都安装在Moodle源代码树中自己的文件夹中。文件夹的位置取决于插件类型和插件名称。所有相同类型的插件都作为一个公共父目录中的子文件夹安装。这个插件类型的父目录的路径定义在lib/components.json文件中。也可以在dev docs Plugin types中找到。
除了出现在用户界面上的可读的插件名(如“分配活动”)外,每个插件都有自己的系统插件名。这是包含该特定插件的所有文件的文件夹的名称。
EXAMPLE
任务分配是一个活动模块。所有活动模块都安装在Moodle源代码树的mod父文件夹中的子文件夹中。赋值的插件名是assign。所以它在Moodle源代码中的完整位置是/mod/assign。
因此,不能同时安装两个相同类型和相同插件名的插件。可以有两个文件夹名称相同的插件,只要它们是不同类型的——因此安装在不同的父文件夹中
每个插件类型都定义了一个简短的系统名称。对于Activity modules,它是mod。对于Blocks,它是block。对于Question types,它是qtype,等等。这些简短的名称定义在lib/components.json文件中。也可以在dev docs Plugin types中找到。
这允许每个安装的Moodle插件都有一个唯一的标识符,由插件类型名(plugin type name)和插件文件夹名(plugin folder name)组成。用下划线符号隔开,这两个组成了所谓的完整组件名(Moodle开发人员非正式地称之为frankenstyle)。
插件的完整组件名称(frankenstyle)在Moodle PHP代码中扮演着重要的角色。说明:
关于这个概念及其在Moodle中的用法的更多细节,请参阅开发文档Frankenstyle。
插件文件夹中的文件实现了插件的逻辑,以及插件和Moodle核心之间所需的接口。每种插件类型都有自己的细节和要求。在所有插件类型中,仍然有许多文件以相同的方式工作。
在这些文件中,最重要的是:
和许多其他这些常见文件。
完整列表请参见dev docs Plugin files。
入乡随俗.jpg
多年来,Moodle开发人员已经就如何格式化和组织代码的某些风格和指导方针达成了一致。在Moodle核心和插件中使用相同的风格有助于我们检查和学习彼此的代码。这可能不是你个人喜欢的风格。不过,在使用Moodle进行开发时,请从最开始就坚持使用它。
In this tutorial we explore:
现代PHP框架提供了自己的处理和路由传入HTTP请求并生成响应的方法。Moodle开发在这些框架出现之前就已经开始了,它使用了典型的传统方法,即服务器端脚本生成动态网页。
从体系结构的角度来看,Moodle可以被看作是实现Page Controller软件设计模式。
“[…] Page Controller is an object (in the broader sense of the term, not only an instance of a class but every kind of item) kept on the server, which is called upon a certain endpoint is the target of a HTTP request. For example, plain old PHP scripts, which you call with URLs like /index.php, /list.php or /folder/member.php?id=42 are Page Controllers.”
Source: Practical PHP Patterns: Page Controller by Giorgio Sironi, July 14, 2010, Web Dev Zone
For more information please see for example Patterns of Enterprise Application Architecture Catalog by Martin Fowler et al.
在Moodle中有两种主要的PHP脚本:
Request handlers(请求处理程序):
这些是页面控制器直接被用户的web浏览器访问。这些脚本是HTTP请求的端点,它们通常打印生成的HTML并执行其他操作。
EXAMPLE: 脚本/课程/视图。访问/course/view.php可以显示课程主页,也可以处理一些与课程相关的操作,比如移动部分moving sections。
Libraries(库):
这些脚本不应该通过HTTP请求直接访问。它们由其他脚本加载,并提供实现所有逻辑的库函数和类定义。
EXAMPLE: 课程视图脚本加载另一个库脚本/lib/completionlib.php,它提供了活动完成api相关的函数。
Request handlers process the incoming HTTP request. In the vast majority of cases, this will either be a GET or a POST request. All request handlers must start by including the main config.php script from the root of the Moodle installation.
require(__DIR__ . '/../../config.php');文件的特定路径将取决于请求处理程序脚本在Moodle文件treę中的深度。
主配置文件定义了一些基本变量,比如数据库连接细节或Moodle数据文件夹的位置。config.php然后加载lib/setup.php文件来设置执行环境:
请参阅开发文档What happens when you require config.php获取更多安装过程的详细信息。
请求处理程序通常在开始时执行的其他事情是:
读取并清除所有输入参数
执行访问控制检查
如果请求即将触发数据库中的更改…
库不应该被浏览器直接访问。它们只能由其他脚本加载 - 要么是请求处理程序,要么是其他库。
传统的库文件应该以下面一行开始:
defined('MOODLE_INTERNAL') || die();这是为了停止脚本的执行,如果库没有被其他脚本加载。常量MOODLE_INTERNAL是在执行环境设置期间定义的。换句话说,这是为了确保config.php文件(因此还有lib/setup.php)已经加载。
请参阅Require/include section of the Coding style,了解如何从另一个文件加载库。
类文件是Moodle中库文件的子集,具有一些特殊的规则。
当前的指南建议对所有新库代码使用有命名空间的类。然而,你仍然会在Moodle核心中看到很多传统的库文件,以及贡献的插件。
请求处理程序负责读取和处理HTTP参数。出于安全原因,Moodle插件不应该访问PHP请求超全局变量,如$_GET、$_POST或$_REQUEST。相反,Moodle core提供了一些辅助函数,如required_param()或optional_param(),它们应该用来读取提交的参数的值。
来自用户的所有输入参数都必须被视为潜在的恶意,必须始终进行消毒和验证。为此,需要指定适当的参数类型。该类型由PARAM_*常量之一指定。最常用的类型有:
请参阅lib/moodlelib.php的源代码,了解更多PARAM类型常量及其内联文档。
Moodle不需要安装在web服务器的HTML文档文件夹的根目录下。许多机构都将他们的Moodle安装在类似于www.ourschool/lms/等子文件夹中。当我们需要Moodle脚本的URL时,我们需要考虑配置变量wwwroot。此外,Moodle支持admin/文件夹的重命名,以避免与一些网络托管平台的冲突。
在Moodle中使用URLs的便捷方式是使用moodle_url类。
moodle_url类实例可以传递给Moodle需要URL的任何函数。核心函数redirect()就是这样一个函数的例子。该类还实现了PHP魔术方法__toString(),因此可以将其视为字符串(String)。
EXAMPLE 显示一个指向给定课程的链接:
$courseid = required_param('courseid', PARAM_INT);$courseviewurl = new moodle_url('/course/view.php', ['id' => $courseid]);echo '<a href="' . $courseviewurl . '">Back to the course</a>';In this tutorial we explore:
代码本身不应该有硬编码的文本。相反,Moodle使用了一种内建机制,允许我们在一个专用文件中定义所有文本字符串。所有应该出现在用户界面中的文本都在插件的字符串文件中定义了一个简单的PHP关联数组。英语字符串必须始终存在,它们可以作为翻译成其他语言的源。
EXAMPLE The file mod/quiz/lang/en/quiz.php provides all texts for the Quiz activity module. Among others there is a line:
$string['editingquiz'] = 'Editing quiz';where the string editingquiz is defined. To display that string somewhere in the user interface, the get_string() core function is used:
echo get_string('editingquiz', 'mod_quiz');通常,在Moodle plugins目录中共享的插件应该只提供英文字符串。它们可以由Moodle社区翻译,翻译包含在Moodle的标准语言包中。
如果你正在开发一个不打算公开分享的插件,你可以自己提供和维护翻译。
除了插件之外,核心子系统还在语言文件中定义了它们的字符串。它们位于Moodle安装目录中的lang/en/文件夹中。
关于如何处理文本字符串及其翻译的更多信息,请参阅开发文档String APl。
Moodle在内部将所有日期和时间存储为Unix时间戳(Unix timestamps),时间戳基本上是1970年1月1日以来的秒数。
要以用户自己的语言格式显示Unix时间戳(与时区无关),可以使用Time APl提供的函数。
最常见的是,您将使用userdate()函数。
$now = time();echo userdate($now);要手动指定显示格式,请使用core_langconfig组件中定义的strftime formatting strings之一。例如,要只显示日期而不显示时间,请使用:
$date = new DateTime("tomorrow", core_date::get_user_timezone_object());$date->setTime(0, 0, 0);echo userdate($date->getTimestamp(), get_string('strftimedatefullshort', 'core_langconfig'));不同的语言在显示小数时使用不同的小数分隔符。使用format_float()核心函数来向用户很好地显示十进制数。实际计算时不要使用此函数!
EXAMPLE 在Moodle中显示的一个典型的十进制数可以是学生的成绩。以小数点后两位的精度显示:
$grade = 20.00 / 3;echo format_float($grade, 2);In this tutorial we explore:
任何Moodle网站上的所有页面都有一些共同的功能,如用户菜单、导航元素或页脚。为了让这些工作正常进行,每个页面都需要知道一些关于自己的信息,例如:
当前显示的页面由moodle_page类(class)的一个实例表示,该实例可以作为$PAGE全局变量用于请求处理脚本。开发文档Page APl描述了类方法、它们的用途以及如何使用它们。
下面的页面介绍了一些我们将在Hello world插件中使用的常用方法。
每个页面都应该有一个唯一的URL。这是应该用来返回到页面的地址,例如,在编辑它的一个块(block)之后。
$PAGE->set_url(new moodle_url('/local/helloworld/index.php));一旦设置了当前页面的URL,我们就可以通过$PAGE->url属性访问它。
echo '<form method="get" action="'.$PAGE->url.'">';它还可以用作其他url的基础。
$nextitemurl = new moodle_url($PAGE->url, ['item' => $nextitemid]);我们必须指定当前页面所属的Moodle上下文。上下文将在本教程后面讨论角色和权限时进行更深入的讨论。出于我们插件的目的,我们将只使用top-level system context。
$PAGE->set_context(context_system::instance());可以通过PAGE->context属性访问为当前页面设置的上下文(context)。
每个页面都应该定义其标题。主题使用它作为页面<head>部分内的<title>标签的值。HTML浏览器使用它作为显示页面的窗口或标签的标题。
$PAGE->set_title(get_string('pluginname', 'local_helloworld'));要定义应显示为页面主标题的文本,请定义标题。
$PAGE->set_heading(get_string('hellouser', 'local_helloworld', $username));页面布局布局描述了Moodle页面的通用结构 - 是否有侧边块区域,是否显示导航栏,是否显示页脚等。所有支持的布局都定义在当前使用的主题或其父主题的theme/.../config.php文件中。常用的布局有base(默认),standard, course, frontpage, mydashboard 和 login。
在一些主题,如Classic,默认的基本布局不显示侧块区域。因此,使用带有侧导航块的标准布局来指定自定义脚本是很常见的。
$PAGE->set_pagelayout('standard');一旦设置好页面,输出呈现机制就有足够的信息来实际生成页面的所有HTML。
要完成DOM初始化并开始输出HTTP头文件和实际的<html>内容,调用
echo $OUTPUT->header();$OUTPUT是Moodle在设置过程中创建的一个有用的全局变量。关于Output APl的全部细节超出了本教程的范围,但是现在,只要知道$OUTPUT是一个输出呈现类的实例,它的目的是生成表示页面及其上所有小部件的HTML,就足够了。
要在页面上打印页脚,关闭</body>和</html>标签,并完成输出呈现,调用
echo $OUTPUT->footer();在将用户提交的所有内容作为页面HTML的一部分显示之前,必须仔细处理。如果内容来自用户,则绝不应该通过简单的echo()调用来显示它。下一章将描述将要使用的一些辅助函数。
应该强调的是,用户提交的内容实际上包括了广泛的数据,包括HTTP查询字符串(HTTP query string)、表单数据(form data)、用户代理字符串(user-agent strings)、cookies、请求引用器(request referrer)等。
在将用户数据包含到页面的HTML源代码中之前,需要调用一些输出帮助函数来处理这些数据。
s() - 这是PHP原生htmlspecialchars()的包装器。它应该用于我们不想解释任何HTML的纯文本。一个典型的例子可能是HTML标记属性的值。
echo '<input type="text" name="uname" value="' . s($uname) . '">';format_string() - 显示短字符串,不使用HTML格式和文本过滤。该字符串由所有配置为应用于网站管理中的“内容和标题”(“Content and headings”)的过滤器处理。用于在课程主页上显示活动模块名称、分组和队列名称、课程名称等文本。
echo format_string($course->name);format_text() - 这是用来显示长格式的文本,应用了所有的filters。Moodle中的丰富文本,例如那些用默认文本编辑器创建的 - 通常已经被格式化为HTML。但根据用户的偏好,情况可能并非总是如此。因此,此函数首先将文本转换为HTML并应用所有过滤器。由此产生的HTML是任何无效的不安全的部分被清除。通过这个函数删除文本的一个典型例子是图书资源中的一个章节或提交到论坛的一个帖子。
该函数接受$options参数来调优预期的行为。例如,可以设置noclean标志来跳过HTML清理,这可以用于内容只能来自可信用户(如课程中的老师)的地方。
echo format_text($post->content, $post->contentformat, ['noclean' => true, 'context' => $context]);下面的流程图可以提供一个粗略的指南,说明在何种情况下使用什么辅助函数,这取决于一些决策。
Moodle附带了一个高级的输出呈现引擎,它鼓励开发人员将PHP脚本中的逻辑处理与通过呈现器(renderers)和模板(templates)生成HTML表示分离开来。除了其他好处外,它允许主题通过覆盖默认的呈现方法和模板来完全控制生成的HTML。
为了实现本教程演示插件的目的,我们可以使用一种更简单的方法,直接从处理请求的PHP脚本生成HTML。
Moodle提供了一个名为html_writer的助手类,它提供了大量的静态方法来从PHP脚本生成HTML。一些常用的方法是html_writer::link()或html_writer::img()。
EXAMPLE 为表单(form)<input>字段生成HTML。
echo html_writer::tag('input', '', ['type' => 'text','name' => 'username','placeholder' => get_string('typeyourname', 'local_helloworld'),]);Author: Lorain.
Completion time: ???