# 模块 / Modules
Pagekit 使用 *模块/Modules* 来组建应用程序的代码。模块的定义是用于提供引导、路由和其他配置选项。可以在这里监听事件、添加自定义类和自己的控制器(controllers)。
## 定义: index.php
为了加载和配置模块,Pagekit 有一个模块管理器(ModuleManager)。模块管理器会在模块的根目录中寻找 `index.php` 文件并期望它返回一个 PHP 数组。该数组用作模块代码的引导。
通过在数组中设置正确的属性,告知 Pagekit 关于模块的所有细节。
```php
<?php
/*
* 返回作为模块定义的 PHP 数组
*/
return [
// Required: Unique module name
'name' => 'hello',
];
```
这个最小的例子是有效的模块定义,即使它被 Pagkit 加载后并不会做任何事。只有在管理面板中启用包,相关的模块才会被加载。
**Note:** 如果你开始探索 Pagekit 的内部结构,你会在许多地方看到相同的模块结构,它是 Pagekit 架构的核心理念。
## 可用的属性
下表包含所有可以在模块定义数组中使用的键名(KEY)。接下来解释了各个属性的详细信息以及相关示例代码。可以点击 *Details* 直接查看相关部分。
|Key | Description | More|
|--------- | --------------------------------- | -----|
|`main` | 引导代码,模块被加载时执行 | [Details](#bootstrap-code)|
|`autoload` | 注册自动加载的命名空间 | [Details](#register-custom-namespaces)|
|`routes` | Mount controllers | [Details](#mount-controllers)|
|`permissions` | 定义和注册权限名称 | [Details](#define-permissions)|
|`resources` | Register resource shorthands | [Details](#register-resource-shorthands)|
|`events` | 监听 Pagekit 或其他模块的事件 | [Details](#listen-to-events)|
|`config` | 默认的模块配置 | [Details](#default-module-configuration)|
|`nodes` | 注册站点树节点 | [Details](#register-nodes-for-site-tree)|
|`node` | 节点配置的默认选项 | [Details](#node-options)|
|`settings` | 链接到设置界面 | [Details](#link-to-a-settings-screen)|
|`menu` | 将菜单条目添加到管理面板 | [Details](#add-menu-items-to-the-admin-panel)|
|`widgets` | 注册小工具 | [Details](#register-widgets)|
|`widget` | 小工具配置的默认选项 | [Details](#widget-options)|
## 引导代码
要执行各种 PHP 代码,你可以为 `main` 属性指派一个回调函数。该函数以参数的形式接收 Pagekit 的 Application 容器实例。
```php
use Pagekit\Application;
// ...
'main' => function (Application $app) {
// bootstrap code
}
```
在每个普通页面请求时,该函数在模块被加载后才被调用。模块的 `index.php` 需要放在可用的包内部,而且需要在管理面板中启用这个包。这意味着扩展需要被安装和启用了才能加载引导代码。如果是在主题内使用它,只有当前激活的主题中的引导代码会被执行。
如果不想指派回调函数和直接把代码存放在 `index.php` 中,你还可以在一个单独的文件里创建一个专用的模块。然后将模块类(module class)的名字(包括命名空间)指定为 `main` 属性的值。
```php
'main' => 'MyNamespace\\MyModule',
```
**Note** 为使其正常工作,这个被引用的命名空间必须被[自动加载](#register-custom-namespaces)。确保`MyModule` 类实现了`Pagekit\Module\ModuleInterface`接口。
## 注册自定义命名空间
传递一个命名空间和路径组成的列表,使它们可以被 Pagekit 自动加载。路径是相对于模块的路径,假设模块定义的位置是在 `packages/VENDOR/PACKAGE/index.php`,那么下面例子中的 `src` 位于 `packages/VENDOR/PACKAGE/src`。
```php
'autoload' => [
'Pagekit\\Hello\\' => 'src'
]
```
被链接的目录中的类,可以通过在 Pagekit 代码库中使用 ``use`` 语句引用。
```
<?php
use Pagekit\Hello\HelloExtension;
```
## 增加控制器
使用 `routes` 熟悉为路由增加控制器。更多细节,阅读[路由和控制器](224133)。
```php
'routes' => [
'/hello' => [
'name' => '@hello/admin',
'controller' => [
'Pagekit\\Hello\\Controller\\HelloController'
]
]
]
```
## 定义权限
你的模块可以定义权限。这些权限可以在 Pagekit 的用户 & 权限界面指定给各种用户角色。
你定义的唯一权限名称(下例中的 `hello: manage settings`),在代码库中被用作标识符。可以使用此标识符可以防止没有权限的用户执行未授权的操作。
```php
'permissions' => [
'hello: manage settings' => [
'title' => 'Manage settings'
]
]
```
保护控制器操作的一个简单方式是像下面的例子中这样,使用注释。阅读[路由](224133)中注释这部分了解更多。
```
<?php
class MyController {
/**
* @Access("hello: manage settings")
*/
public function settingsAction() {
}
}
```
## 注册源代码简写方式
可以注册前缀,作为处理路径时的简写方式。例如使用 `views:admin/settings.php` 来引用 `packages/VENDOR/PACKAGE/views/admin/settings.php`。Pagekit 已经默认为扩展和主题注册了一些路径了。
无论何时,只要在使用 Pagekit 文件系统,它都会工作(例如,在生成文件路径的 URL 时,或者从控制器渲染视图时)。
```php
'resources' => [
'views:' => 'views'
],
```
## 事件监听
事件是在 Pagekit 核心或其他潜在的模块的某些关键点上触发的。每个事件都有一个独一无二的名称来定义它。可以为任意事件注册回调函数。
了解关于事件系统的更多信息,查阅[事件](224132)。
```php
'events' => [
'view.scripts' => function ($event, $scripts) {
$scripts->register('hello-settings', 'hello:app/bundle/settings.js', '~extensions');
}
]
```
## 默认的模块配置
在许多情况下,你希望允许用户修改模块的设置,例如提供一个设置页面。要确保你的模块一开始就有配置的值,你可以提供一套默认的模块配置。
```php
'config' => [
'default' => 'World'
],
```
任何对于配置数组的修改,都会在稍后存储到数据库。然后,默认值会与数据库中的值合并,合并后的结果可用作模块对象的配置属性,如你在下面两节的例子所见。
### 读取配置
要读取模块的配置,可以访问模块实例的 `config` 属性。它是`index.php`中保存的默认配置和存储在数据库中的修改值的合并结果。
```php
$config = $app->module('hello')->config;
```
### 写入配置
要存储模块配置的修改,使用 `config()` 服务。这些修改会自动传输到数据库。
```php
// Complete config
$app->config()->set('hello', $config);
// Single Value
$app->config('hello')->set('message', 'Custom message');
```
**Note**. 如果直接从模块中读取配置,它依然是原来的值。在下一次请求后,Pagekit 会合并修改,并使它们可用作 `$module` 实例的 `config` 属性。
## 注册站点树节点
节点(Node)与路由的最大区别在于,节点可以在站点树视图(Site Tree View)中拖拽,并因此导致了计算出的路由的结果是动态的。
在添加节点之后,它将在站点树中可用。点击 _Add Page_ 按钮查看包含所有可用类型的下拉菜单。
了解关于节点的更多信息,查阅[路由](224133)。
```php
'nodes' => [
'hello' => [
// 节点路由的名称
'name' => '@hello',
// 显示在管理面板中的标签
'label' => 'Hello',
// 此节点的控制器。每个控制器操作都会被附加到路由
'controller' => 'Pagekit\\Hello\\Controller\\SiteController'
]
]
```
## 节点选项
在站点树中,如果模块想要为内容编辑器添加一个配置界面,可以使用 `node` 属性来添加默认选项到节点对象(关于配置界面的完整说明,查阅[主题教程](../tutorials/theme.md#adding-position-options))。
在下面的例子中,主题定义了自动添加到每个已渲染的节点对象的 `top_style` 属性。在下面的例子中,该属性有一个默认值 `uk-block-muted`,它是渲染 `top`位置的 CSS 类。
```php
'node' => [
'top_style' => 'uk-block-muted'
],
```
在主题的 `template.php` 中渲染页面时,可以从 `$params` 数组访问这个对象。
```php
<?php echo $params['top_style'] ?>
```
利用 `node` 属性,可以为每个节点设置默认值。要允许用户修改这些值,你需要在管理界面中添加一个界面(典型的形式是编辑页面内容时的 _Theme_ 标签页)。
要允许用户修改你在这里定义的小工具的默认值,可以为管理界面添加一个界面。为此,需要定义一个 javascript 组件来显示编辑页面([Example](https://github.com/pagekit/example-theme/blob/master/app/components/node-theme.vue)),在内容编辑页面注册这个 javascript ([Example](https://github.com/pagekit/example-theme/blob/master/index.php#L43)) ,如果你在使用 webpack,可选择地更新 webpack 配置([Example](https://github.com/pagekit/example-theme/blob/master/webpack.config.js#L5))。完整的说明可以参阅 [主题教程](../tutorials/theme.md#adding-position-options).
## 添加菜单条目到管理面板
可以为管理面板的主导航添加菜单条目。可以将它链接到任意已注册的路由并赋予有限的访问权限。`access` 属性会确认菜单条目是否可见。
```php
'menu' => [
// 用于菜单结构层次的名称
'hello' => [
// 要显示的表情
'label' => 'Hello',
// 要显示的图标
'icon' => 'hello:icon.svg',
// 此菜单条目链接到的 URL
'url' => '@hello/admin',
// 可选:检查菜单项是否在当前 url 是激活的
// 'active' => '@hello*'
// 可选: 针对被指定特定权限的角色的访问限制
// 'access' => 'hello: manage hellos'
],
'hello: panel' => [
// 父级菜单项,使此项显示在二级菜单中
'parent' => 'hello',
// See above
'label' => 'Hello',
'icon' => 'hello:icon.svg',
'url' => '@hello/admin'
// 'access' => 'hello: manage hellos'
]
],
```
## 链接到设置页面
链接到渲染设置页面的路由。设置这个属性使 Pagekit 在控制面板列表中的主题或扩展旁渲染一个 _Settings_ 按钮。
```php
'settings' => '@hello/admin/settings',
```
## 注册小工具
小工具也是一种模块。使用 `widgets` 小工具可以注册所有小工具模块的定义文件。这些文件都被预期返回一个模块定义格式的 PHP 数组。了解更多关于[小工具](224139)。
```php
'widgets' => [
'widgets/form.php'
],
```
## 小工具选项
如果模块想要为小工具编辑器添加一个配置界面(通常是在开发主题时),可以使用 `widget` 属性来为小工具对象添加默认选项(小工具配置界面的完整例子在[开发 Pagekit 主题](223157)中)。
下面的例子中,主题定义了一个自动添加到每个已渲染的小工具对象的 `panel` 属性。默认地,该属性以空字符串作为它的值。
```php
'widget' => [
'panel' => ''
],
```
在渲染小工具时,可以在 `$widget->theme` 数组中访问这个属性。
```php
<?php echo $widget->theme['panel'] ?>
```
要允许用户修改你在这里定义的小工具选项的默认值,可以在管理界面中添加一个界面。为此,可以定义一个 javascript组件来显示编辑界面([Example](https://github.com/pagekit/example-theme/blob/master/app/components/widget-theme.vue)),在小工具编辑器页面注册这个 javascript 文件 ([Example](https://github.com/pagekit/example-theme/blob/master/index.php#L47)) ,如果你在使用webpack([Example](https://github.com/pagekit/example-theme/blob/master/webpack.config.js#L7)),可以有选择地更新 webpack 的配置。完整的说明可以在这里找到:[主题教程](223157).