# 模塊 / 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).