- 此模块开发所使用的容器是91上师姐的 wzz-drupal10-tripal 容器,Drupal版本是Drupal10.1
- 并且在路径/var/www/drupal/web/modules下下载了官方D10的模块开发example模块(example目录下),自己的测试模块在custom目录下
1.在学习如何写模块前,首先需要了解Symfony,它是一个 PHP 框架,基于其最佳 WEB 开发实践,帮助快速开发 PHP 应用。而Drupal 8及以上版本(从Drupal 8 开始实现了面向对象架构,更具灵活性。Drupal 8 的灵活性增强,部分得益于把 Symfony 框架作为其核心的一部分。Symfony 有几十个独立的库,这些库可以应用于任何 PHP 项目。)借助 Symfony 的代码构建路由和控制器,当然这些代码并不是专门为 Drupal 开发,而是按照通用标准实现的。所以对于我们而言使用它是编写路由routing和控制器controller基础所依赖的代码库。Symfony 引入的一个最有用的工具是能够根据位置自动加载代码。
也就是说现在 Drupal 开发无需再创建一个完整的 include 文件,只一个 use 行便可包含可重用代码。
2.路由、路由器和控制器
路由(routing):我们通过Symfony可以自己定义创造URL,映射到应用的不同区域。一个路由是从一个 URL 路径到一个控制器的映射(我对于这句话的理解就是我们可以在路由里面自定义我们想展示页面或者区域的URL,也就是地址栏)。
控制器(controller):一个控制器就是一个 PHP 函数,用于处理 HTTP 请求(HTTP request),构造并返回一个 HTTP 响应 (HTTP response,比如 Symfony Responseobject)。响应可以是一个 HTML 页面,一个 XML 文档, 一个序列化的 JSON 数组,一个图片,一个重定向,一个 404 错误或者任何你能想到的东西。 控制器可以包含呈现页面内容的任何逻辑。PS:在我编写模块的过程中,看到社区中的人建议控制器中最好还是只包含函数关系等一些功能性的代码,而非HTML这类展示型的内容。
3.创建一个简单模块
现在基于官方的 Examples 创建一个简单模块,现在大多数模块结构基于 YAML。
3.1 创建目录
首先需要在modules目录下面创建一个我们自己的模块的目录(如果后续其他模块也要放在这个package里面就需要这个作为公共目录)my_module;接着在这个公共目录里面创建我们第一个模块(比如叫page_example)的目录(算是这个模块的根目录),路径在
3.2 创建 page_example.info.yml 文件
最先需要编写的就是模块的info文件,在模块根目录下面创建一个page_example.info.yml的文件,里面主要包括name(模块名称)、type(一般就是module)、description(模块功能的简要描述)、package(归属于哪个包下面)、core_version_requirement(所支持的drupal版本,这个很重要,如果版本不匹配这个模块就不会被drupal所添加)这几个主要内容,其他类似于模块的version什么的也可以按需添加。此时已经可以在网站的模块里面找到这个模块并且勾选加载了,只是它还没有任何功能罢了。 这里需要注意一点,在D8的教程中,info文件定义如下
name: 'Page example'
type: module
description: 'An example module showing how to define a page to be displayed at a given URL.'
package: 'Example modules'
core: 8.x
这里有个问题,教程是D8的,D10在这里声明版本时候不是core了,变成了core_version_requirement,否则会报错:Drupal\Core\Extension\InfoParserException: The 'core_version_requirement' key must be present in modules/examples/page_example/page_example.info.yml in Drupal\Core\Extension\InfoParserDynamic->parse() (line 67 of core/lib/Drupal/Core/Extension/InfoParserDynamic.php).
而D10的 info 文件内容如下,供对比参考:
name: Test Page
type: module
description: 'Provides a test page with some text.'
package: Custom
version: 1.0.0
core_version_requirement: ^10 || ^11
3.3 创建 page_example.routing.yml 文件
test_page_simple1:
path: '/test/test-page/simple1'
defaults:
_controller: '\Drupal\test_page\Controller\TestPageController::simple1'
_title: 'Test Page'
requirements:
_permission: 'access simple1 page
test_page_simple1: 为 test page 模块定义一个新路由。
path: 路由注册的路径,等价于 Drupal 7 中 hook_menu() 内 $items[] 数组的 key。 需要以斜线开头,详细请查看文档 structure of routes 。
controller: 定义路由的路径对应 TestPageController 控制器的 description 方法。content 变为 _controller 这个比较有趣,这使 Drupal 8 与 Symfony 更同步。
requirements:用户能够访问这个页面所具有的权限。这个权限也有点重要
想使用额外的路由选项,请查看 Structure of routes 文档页。(这个路由部分挺有意思的,后面详细需要了解一下,感觉比较重要,在我的理解中像一个URL指向或者定义函数功能)
3.4 创建 PageExampleController.php 文件(比较重要)
在Drupal模块里,采用了部分 PSR-4 标准,控制器和其他类被要求放在 src/ 目录。首先在模块目录创建放置控制器的目录 src/Controller,接着创建控制器文件 TestPageController.php ,最后在文件内声明 TestPageController 控制器类,文件如下:
<?php
namespace Drupal\test_page\Controller;
use Drupal\Core\Url;
/**
* Controller routines for page example routes.
*/
class TestPageController {
/**
* Constructs a page with descriptive content.
*
* Our router maps this method to the path 'examples/page_example'.
*/
public function description1() {
$simple1_url = Url::fromRoute('test_page_simple1');
/* $simple1_link = \Drupal::l(t('simple1 page'), $simple1_url);
$build1 = [
'#markup' => t(
'<p>The Page example module provides two pages, "simple" and "arguments".</p>'
. '<p>The !simple_link just returns a renderable array for display.</p>'
. '<p>The !arguments_link takes two arguments and displays them, as in @arguments_url</p>',
[
'!simple1_link' => $simple1_link
]
),
];
return $build1;
}
/**
* Constructs a simple page.
*
* The router _controller callback, maps the path 'examples/page_example/simple'
* to this method.
*
* _controller callbacks return a renderable array for the content area of the
* page. The theme system will later render and surround the content with the
* appropriate blocks, navigation, and styling.
*/
public function simple1() {
return [
'#markup' => '<p>' . t('welcome to test page') . '</p>',
];
}
}
在上述代码中有一个比较重要的NameSpace(名字空间):尽管名字空间可以包含任何有效的 PHP 代码,但名字空间只会影响以下代码类型: 类(包括 abstracts 和 traits 类),接口,函数和常量。 名字空间使用 namespace 关键字进行声明。 包含名字空间的文件必须在文件的顶部、任何其他代码(declare 关键字除外)之前进行名字空间的声明。参阅 Defining Namespaces 。
声明了名字空间后,我们便可以通过 use 操作符引入这些类,以便使用它们的方法。使用别名引用外部的一个完全限定名是名字空间的重要特征。 这类似 Linux 文件系统中为文件或目录创建符号链接一样。 而在PHP 中别名通过 use 操作符完成。参阅Using namespaces: Aliasing/Importing
这里又存在一个问题就是怎么知道名字空间和 use 操作符的路径?
其实,名字空间就是文件所在位置的路径,之后使用这个作为 use 操作符使用的别名。
类文件类似这样:namespace Drupal\page_example\Controller;
另一个要使用它的文件类似这样:use Drupal\page_example\Controller
之后你就可以使用 Controller 目录下的文件了。
3.5 创建 page_example.links.menu.yml 文件
这部分暂时没有用到,只构建一个简单的页面显示模块
3.6 重构缓存
进行改动后需要进行站点清除缓存的操作,如果要通过命令行重建站点、清空缓存,需要使用最新版本的 drush命令: drush rc
3.7 测试
10.202.40.91:8081/test/test-page/simple1,在应用模块后可以在这里看到我们创建的页面输出welcome to test page
是删掉了么?
下次把金山文档的链接也放上,那里点评的时候看起来更直接。