# 事件廣播
- [簡介](#introduction)
- [配置](#configuration)
- [對驅動器的要求](#driver-prerequisites)
- [概念綜述](#concept-overview)
- [使用示例程序](#using-example-application)
- [定義廣播事件](#defining-broadcast-events)
- [廣播數據](#broadcast-data)
- [廣播隊列](#broadcast-queue)
- [頻道授權](#authorizing-channels)
- [定義授權路由](#defining-authorization-routes)
- [定義授權回調](#defining-authorization-callbacks)
- [對事件進行廣播](#broadcasting-events)
- [只廣播給他人](#only-to-others)
- [接收廣播](#receiving-broadcasts)
- [安裝 Laravel Echo](#installing-laravel-echo)
- [對事件進行監聽](#listening-for-events)
- [命名空間](#namespaces)
- [Presence 頻道](#presence-channels)
- [授權 Presence 頻道](#authorizing-presence-channels)
- [加入 Presence 頻道](#joining-presence-channels)
- [廣播到 Presence 頻道](#broadcasting-to-presence-channels)
- [消息通知](#notifications)
<a name="introduction"></a>
## 簡介
在現代的 web 應用程序中,WebSockets 被用來實現需要實時、即時更新的接口。當服務器上的數據被更新后,更新信息將通過 WebSocket 連接發送到客戶端等待處理。相比于不停地輪詢應用程序,WebSocket 是一種更加可靠和高效的選擇。
為了幫助你建立這類應用,Laravel 將通過 WebSocket 連接來使「廣播」[事件](/docs/{{version}}/events) 變得更加輕松。廣播事件允許你在服務端代碼和客戶端 JavaScript 應用之間共享相同的事件名。
> {tip} 在深入了解事件廣播之前,請確認你已閱讀所有關于 Laravel [事件和偵聽器](/docs/{{version}}/events) 的文檔。
<a name="configuration"></a>
### 配置
所有關于事件廣播的配置都被保存在 `config/broadcasting.php` 文件中。Larevel 自帶了幾個廣播驅動器:[Pusher](https://pusher.com), [Redis](/docs/{{version}}/redis), 和一個用于本地開發與調試的 `log` 驅動器。另外,還有一個 `null` 驅動器可以讓你完全關閉廣播功能。每一個驅動的示例配置都可以在 `config/broadcasting.php` 文件中被找到。
#### 廣播服務提供者
在對事件進行廣播之前,你必須先注冊 `App\Providers\BroadcastServiceProvider`。對于一個全新安裝的 Laravel 應用程序,你只需在 `config/app.php` 配置文件的 `providers` 數組中取消對該提供者的注釋即可。該提供者將允許你注冊廣播授權路由和回調。
#### CSRF 令牌
[Laravel Echo](#installing-laravel-echo) 會需要訪問當前會話的 CSRF 令牌。如果可用,Echo 會從 `Laravel.csrfToken` JavaScript 對象中獲取該令牌。如果你運行了 `make:auth` Artisan 命令,該對象會在 `resources/views/layouts/app.blade.php` 布局文件中被定義。如果你未使用該布局文件,可以在應用程序的 `head` HTML 元素中定義一個 `meta` 標簽:
```html
<meta name="csrf-token" content="{{ csrf_token() }}">
```
<a name="driver-prerequisites"></a>
### 對驅動器的要求
#### Pusher
如果你使用 [Pusher](https://pusher.com) 對事件進行廣播,請用 Composer 包管理器來安裝 Pusher PHP SDK:
```bash
composer require pusher/pusher-php-server
```
然后,你需要在 `config/broadcasting.php` 配置文件中填寫你的 Pusher 證書。該文件中已經包含了一個 Pusher 示例配置,你只需指定 Pusher key、secret 和 application ID 即可。
當把 Pusher 與 [Laravel Echo](#installing-laravel-echo) 一起使用時,你應該在實例化 Echo 對象時指定 broadcaster 為 `pusher`:
```js
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key'
});
```
#### Redis
如果你使用 Redis 廣播器,請安裝 Predis 庫:
```bash
composer require predis/predis
```
Redis 廣播器會使用 Redis 的「生產者/消費者」特性來廣播消息;盡管如此,你仍需將它與 WebSocket 服務器一起使用。WebSocket 服務器會從 Redis 接收消息,然后再將消息廣播到你的 WebSocket 頻道上去。
當 Redis 廣播器發布一個事件時,該事件會被發布到它指定的頻道上去,傳輸的數據是一個采用 JSON 編碼的字符串。該字符串包含了事件名、`data` 數據和生成該事件套接字 ID 的用戶(如果可用的話)。
#### Socket.IO
如果你想把 Redis 廣播器和 Socket.IO 服務器一起使用,你需要將 Socket.IO JavaScript 客戶端庫文件包含到應用程序的 `head` HTML 元素中:
```js
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
```
接著,你需要在實例化 Echo 時指定 `socket.io` 連接器和 `host` 。例如,如果你的應用程序和套接字服務器運行在 `app.dev` 域名上,你應該像這樣實例化 Echo:
```js
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://app.dev:6001'
});
```
最后,你需要運行一個與 Laravel 兼容的 Socket.IO 服務器。Laravel 官方并沒有實現 Socket.IO 服務器;不過,可以選擇一個由社區驅動維護的項目 [tlaverdure/laravel-echo-server](https://github.com/tlaverdure/laravel-echo-server),目前托管在 GitHub。
#### 對隊列的要求
在開始廣播事件之前,你還需要配置和運行 [隊列偵聽器](/docs/{{version}}/queues)。所有的事件廣播都是通過隊列任務來完成的,因此應用程序的響應時間不會受到明顯影響。
<a name="concept-overview"></a>
## 概念綜述
Laravel 的事件廣播允許你使用基于驅動的 WebSockets 將服務端的 Larevel 事件廣播到客戶端的 JavaScript 應用程序。當前的 Laravel 自帶了 [Pusher](http://pusher.com) and Redis 驅動。通過使用 [Laravel Echo](#installing-laravel-echo) 的 Javascript 包,我們可以很方便地在客戶端消費事件。
事件通過「頻道」來廣播,這些頻道可以被指定為公開的或私有的。任何訪客都可以訂閱一個不需要認證和授權的公開頻道;然而,如果想訂閱一個私有頻道,那么該用戶必須通過認證,并獲得該頻道的授權。
<a name="using-example-application"></a>
### 使用示例程序
讓我們先用一個電子商務網站作為例子來概覽一下事件廣播。我們不會討論如何配置 [Pusher](http://pusher.com) 和 [Laravel Echo](#echo) 的細節,因為這些會在本文檔的其他章節被詳細介紹。
在我們的應用程序中,讓我們假設有一個允許用戶查看訂單配送狀態的頁面。有一個 `ShippingStatusUpdated` 事件會在配送狀態更新時被觸發:
```php
event(new ShippingStatusUpdated($update));
```
#### `ShouldBroadcast` 接口
當用戶在查看自己的訂單時,我們不希望他們必須通過刷新頁面才能看到狀態更新。我們希望一旦有更新時就主動將更新信息廣播到客戶端。所以,我們必須讓 `ShippingStatusUpdated` 事件實現 `ShouldBroadcast` 接口。這會讓 Laravel 在事件被觸發時廣播該事件:
```php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ShippingStatusUpdated implements ShouldBroadcast
{
//
}
```
`ShouldBroadcast` 接口要求事件實現 `broadcastOn` 方法。該方法負責指定事件被廣播到哪些頻道。在通過 Artisan 命令生成的事件類中,一個空的 `broadcastOn` 方法已經被預定義好了,所以我們要做的僅僅是指定頻道。我們希望只有訂單的創建者能夠看到狀態更新,所以我們要把該事件廣播到與這個訂單綁定的私有頻道上去:
```php
/**
* 指定事件在哪些頻道上進行廣播
*
* @return array
*/
public function broadcastOn()
{
return new PrivateChannel('order.'.$this->update->order_id);
}
```
#### 頻道授權
記住,用戶只有在被授權后才能監聽私有頻道。我們可以在 `BroadcastServiceProvider` 文件的 `boot` 方法中定義頻道的授權規則。在本例中,我們需要對試圖監聽私有 `order.1` 頻道的所有用戶進行驗證,確保只有訂單的創建者才能進行監聽:
```php
Broadcast::channel('order.*', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
```
`channel` 方法接收兩個參數:頻道名稱和一個回調函數,該回調通過返回 `true` 或 `false` 來表示用戶是否被授權監聽該頻道。
所有的授權回調接收當前被認證的用戶作為第一個參數,任何額外的通配符參數作為后續參數。在本例中,我們使用 `*` 符號來表示頻道名稱的「ID」部分是通配符。
#### 對事件廣播進行監聽
接下來,就只剩下在 JavaScript 應用程序中監聽事件了。我們可以使用 Laravel Echo 來實現。首先,使用 `private` 方法來訂閱私有頻道。然后,使用 `listen` 方法來監聽 `ShippingStatusUpdated` 事件。默認情況下,事件的所有公有屬性會被包括在廣播事件中:
```js
Echo.private('order.' + orderId)
.listen('ShippingStatusUpdated', (e) => {
console.log(e.update);
});
```
<a name="defining-broadcast-events"></a>
## 定義廣播事件
要告知 Laravel 一個給定的事件是廣播類型,只需在事件類中實現 `Illuminate\Contracts\Broadcasting\ShouldBroadcast` 接口即可。該接口已經被導入到所有由框架生成的事件類中,所以你可以很方便地將它添加到你自己的事件中。
`ShouldBroadcast` 接口要求你實現一個方法:`broadcastOn`。`broadcastOn` 方法返回一個頻道或一個頻道數組,事件會被廣播到這些頻道。頻道必須是 `Channel`、`PrivateChannel` 或 `PresenceChannel` 的實例。`Channel` 實例表示任何用戶都可以訂閱的公開頻道,而 `PrivateChannels` 和 `PresenceChannels` 則表示需要 [頻道授權](#authorizing-channels) 的私有頻道:
```php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ServerCreated implements ShouldBroadcast
{
use SerializesModels;
public $user;
/**
* 創建一個新的事件實例
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* 指定事件在哪些頻道上進行廣播
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'.$this->user->id);
}
}
```
然后,你只需要像你平時那樣 [觸發事件](/docs/{{version}}/events)。一旦事件被觸發,一個 [隊列任務](/docs/{{version}}/queues) 會自動廣播事件到你指定的廣播驅動器上。
<a name="broadcast-data"></a>
### 廣播數據
當一個事件被廣播時,它所有的 `public` 屬性會自動被序列化為廣播數據,這允許你在你的 JavaScript 應用中訪問事件的公有數據。因此,舉個例子,如果你的事件有一個公有的 `$user` 屬性,它包含了一個 Elouqent 模型,那么事件的廣播數據會是:
```json
{
"user": {
"id": 1,
"name": "Patrick Stewart"
...
}
}
```
然而,如果你想更細粒度地控制你的廣播數據,你可以添加一個 `broadcastWith` 方法到你的事件中。這個方法應該返回一個數組,該數組中的數據會被添加到廣播數據中:
```php
/**
* 指定廣播數據
*
* @return array
*/
public function broadcastWith()
{
return ['id' => $this->user->id];
}
```
<a name="broadcast-queue"></a>
### 廣播隊列
默認情況下,每一個廣播事件都被添加到默認的隊列上,默認的隊列連接在 `queue.php` 配置文件中指定。你可以通過在事件類中定義一個 `broadcastQueue` 屬性來自定義廣播器使用的隊列。該屬性用于指定廣播使用的隊列名稱:
```php
/**
* 指定事件被放置在哪個隊列上
*
* @var string
*/
public $broadcastQueue = 'your-queue-name';
```
<a name="authorizing-channels"></a>
## 頻道授權
對于私有頻道,用戶只有被授權后才能監聽。實現過程是用戶向你的 Laravel 應用程序發起一個攜帶頻道名稱的 HTTP 請求,你的應用程序判斷該用戶是否能夠監聽該頻道。在使用 [Laravel Echo](#installing-laravel-echo) 時,上述 HTTP 請求會被自動發送;盡管如此,你仍然需要定義適當的路由來響應這些請求。
<a name="defining-authorization-routes"></a>
### 定義授權路由
幸運的是,我們可以在 Laravel 里很容易地定義路由來響應頻道授權請求。在 `BroadcastServiceProvider` 中,你會看到一個對 `Broadcast::routes` 方法的調用。該方法會注冊 `/broadcasting/auth` 路由來處理授權請求:
```php
Broadcast::routes();
```
`Broadcast::routes` 方法會自動把它的路由放進 `web` 中間件組中;另外,如果你想對一些屬性自定義,可以向該方法傳遞一個包含路由屬性的數組:
```php
Broadcast::routes($attributes);
```
<a name="defining-authorization-callbacks"></a>
### 定義授權回調
接下來,我們需要定義真正用于處理頻道授權的邏輯。和定義授權路由一樣,這也是在 `BroadcastServiceProvider` 的 `boot` 方法中完成。在該方法中,你可以用 `Broadcast::channel` 方法來注冊頻道授權回調函數:
```php
Broadcast::channel('order.*', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
```
`channel` 方法接收兩個參數:頻道名稱和一個回調函數,該回調通過返回 `true` 或 `false` 來表示用戶是否被授權監聽該頻道。
所有的授權回調接收當前被認證的用戶作為第一個參數,任何額外的通配符參數作為后續參數。在本例中,我們使用 `*` 符號來表示頻道名稱的「ID」部分是通配符。
<a name="broadcasting-events"></a>
## 對事件進行廣播
一旦你已經定義好了一個事件并實現了 `ShouldBroadcast` 接口,剩下的就是使用 `event` 函數來觸發該事件。事件分發器會識別出實現了 `ShouldBroadcast` 接口的事件并將它們加入到隊列進行廣播:
```php
event(new ShippingStatusUpdated($update));
```
<a name="only-to-others"></a>
### 只廣播給他人
當創建一個使用到事件廣播的應用程序時,你可以用 `broadcast` 函數來替代 `event` 函數。和 `event` 函數一樣,`broadcast` 函數將事件分發到服務端偵聽器:
```php
broadcast(new ShippingStatusUpdated($update));
```
不同的是 `broadcast` 函數有一個 `toOthers` 方法允許你將當前用戶從廣播接收者中排除:
```php
broadcast(new ShippingStatusUpdated($update))->toOthers();
```
為了更好地理解什么時候使用 `toOthers` 方法,讓我們假設有一個任務列表的應用程序,用戶可以通過輸入任務名稱來新建任務。為了新建任務,你的應用程序需要發起一個請求到 `/task` 路由,該路由在接收到請求并成功創建新任務后會觸發一個任務被新建的事件廣播,并返回新任務的 JSON 響應。當你的 JavaScript 應用程序接收到來自該路由的響應時,它會直接將新任務插入到任務列表,就像這樣:
```js
this.$http.post('/task', task)
.then((response) => {
this.tasks.push(response.data);
});
```
然而,別忘了我們還將接收到一個事件廣播。如果你的 JavaScript 應用程序同時監聽該事件以便添加新任務到任務列表,你將會在你的列表中看到重復的任務:一份來自路由響應,另一份來自廣播。
你可以通過使用 `toOthers` 方法讓廣播器只廣播事件到其他用戶來解決該問題。
#### 配置
當你實例化 Laravel Echo 實例時,一個套接字 ID 會被指定到該連接。如果你使用 [Vue](https://vuejs.org) 和 Vue Resource,套接字 ID 會自動被添加到每一個請求的 `X-Socket-ID` 頭中。然后,當你調用 `toOthers` 方法時,Laravel 會從頭中提取出套接字 ID,并告訴廣播器不要廣播任何消息到該套接字 ID 的連接上。
如果你沒有使用 Vue 和 Vue Resource,則需要手動配置 JavaScript 應用程序來發送 `X-Socket-ID` 頭。你可以用 `Echo.socketId` 方法來獲取套接字 ID:
```js
var socketId = Echo.socketId();
```
<a name="receiving-broadcasts"></a>
## 接收廣播
<a name="installing-laravel-echo"></a>
### 安裝 Laravel Echo
Laravel Echo 是一個 JavaScript 庫,它使得訂閱頻道和監聽由 Laravel 廣播的事件變得非常容易。你可以通過 NPM 包管理器來安裝 Echo。在本例中,因為我們將使用 Pusher 廣播器,請安裝 `pusher-js` 包:
```bash
npm install --save laravel-echo pusher-js
```
一旦 Echo 被安裝好,你就可以在你應用程序的 JavaScript 中創建一個全新的 Echo 實例。做這件事的一個理想地方是在 `resources/assets/js/bootstrap.js` 文件的底部,Laravel 框架自帶了該文件:
```js
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key'
});
```
<a name="listening-for-events"></a>
### 對事件進行監聽
一旦你安裝好并實例化了 Echo,你就可以開始監聽事件廣播了。首先,使用 `chennel` 方法來獲取一個頻道實例,然后調用 `listen` 方法來監聽指定的事件:
```js
Echo.channel('orders')
.listen('OrderShipped', (e) => {
console.log(e.order.name);
});
```
如果你想監聽私有頻道上的事件,請使用 `private` 方法。你可以通過鏈式調用 `listen` 方法來監聽一個頻道上的多個事件:
```js
Echo.private('orders')
.listen(...)
.listen(...)
.listen(...);
```
<a name="namespaces"></a>
### 命名空間
你可能注意到了在上面的例子中我們沒有為事件類指定完整的命名空間。這是因為 Echo 會自動認為事件在 `App\Events` 命名空間下。你可以在實例化 Echo 的時候傳遞一個 `namespace` 配置選項來指定根命名空間:
```js
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key',
namespace: 'App.Other.Namespace'
});
```
另外,你也可以在使用 Echo 訂閱事件的時候為事件類加上 `.` 前綴。這時需要填寫完全限定名稱的類名:
```js
Echo.channel('orders')
.listen('.Namespace.Event.Class', (e) => {
//
});
```
<a name="presence-channels"></a>
## Presence 頻道
Presence 頻道是在私有頻道的安全性基礎上,額外暴露出有哪些人訂閱了該頻道。這使得它可以很容易地建立強大的、協同的應用,如當有一個用戶在瀏覽頁面時,通知其他正在瀏覽相同頁面的用戶。
<a name="joining-a-presence-channel"></a>
### 授權 Presence 頻道
Presence 頻道也是私有頻道;因此,用戶必須 [獲得授權后才能訪問他們](#authorizing-channels)。與私有頻道不同的是,在給 presence 頻道定義授權回調函數時,如果一個用戶已經加入了該頻道,那么不應該返回 `true`,而應該返回一個關于該用戶信息的數組。
由授權回調函數返回的數據能夠在你的 JavaScript 應用程序中被 presence 頻道事件偵聽器所使用。如果用戶沒有獲得加入該 presence 頻道的授權,那么你應該返回 `false` 或 `null`:
```php
Broadcast::channel('chat.*', function ($user, $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});
```
<a name="joining-presence-channels"></a>
### 加入 Presence 頻道
你可以用 Echo 的 `join` 方法來加入 presence 頻道。`join` 方法會返回一個實現了 `PresenceChannel` 的對象,它通過暴露 `listen` 方法,允許你訂閱 `here`、`joining` 和 `leaving` 事件。
```js
Echo.join('chat.' + roomId)
.here((users) => {
//
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
});
```
`here` 回調函數會在你成功加入頻道后被立即執行,它接收一個包含用戶信息的數組,用來告知當前訂閱在該頻道上的其他用戶。`joining` 方法會在其他新用戶加入到頻道時被執行,`leaving` 會在其他用戶退出頻道時被執行。
<a name="broadcasting-to-presence-channels"></a>
### 廣播到 Presence 頻道
Presence 頻道可以像公開和私有頻道一樣接收事件。使用一個聊天室的例子,我們要把 `NewMessage` 事件廣播到聊天室的 presence 頻道。要實現它,我們將從事件的 `broadcastOn` 方法中返回一個 `PresenceChannel` 實例:
```php
/**
* 指定事件在哪些頻道上進行廣播
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('room.'.$this->message->room_id);
}
```
和公開或私有事件一樣,presence 頻道事件也能使用 `broadcast` 函數來廣播。同樣的,你還能用 `toOthers` 方法將當前用戶從廣播接收者中排除:
```php
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();
```
你可以通過 Echo 的 `listen` 方法來監聽 join 事件:
```js
Echo.join('chat.' + roomId)
.here(...)
.joining(...)
.leaving(...)
.listen('NewMessage', (e) => {
//
});
```
<a name="notifications"></a>
## 消息通知
將 [消息通知](/docs/{{version}}/notifications) 和事件廣播一同使用,你的 JavaScript 應用程序可以在不刷新頁面的情況下接收新的消息通知。首先,請先閱讀關于如何使用 [廣播消息通知頻道](/docs/{{version}}/notifications#broadcast-notifications) 的文檔。
一旦你將一個消息通知配置為使用廣播頻道,你需要使用 Echo 的 `notification` 方法來監聽廣播事件。頻道名稱應該和接收消息通知的實體類名相匹配:
```js
Echo.private('App.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});
```
在本例中,所有通過 `broadcast` 頻道發送到 `App\User` 實例的消息通知都會被該回調接收到。一個針對 `App.User.*` 頻道的授權回調函數已經被包含在 Laravel 的 `BroadcastServiceProvider` 中了。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@魚肚](http://yudu.tech) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/2613_1473692997.jpg?imageView2/1/w/100/h/100"> | 翻譯 | PHPer of [微貝](http://www.webei.cn/)
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 錯誤與日志
- 開發環境
- HomeStead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- 門面(facades)
- contracts
- HTTP層
- 路由
- 中間件
- CSRF保護
- 控制器
- 請求
- 響應
- Session
- 表單驗證
- 視圖與模板
- 視圖
- Blade模板
- 本地化
- Javascript與CSS
- 入門指南
- laravel-elixir
- 安全
- 用戶認證
- 用戶授權
- 重置密碼
- API授權
- 加密解密
- 哈希
- 綜合話題
- 廣播系統
- 緩存系統
- 事件系統
- 文件存儲
- 郵件發送
- 消息通知
- 隊列
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent集合
- 修改器
- 序列化
- Artisan控制臺
- Artisan 命令行
- 任務調度
- 測試
- 快速入門
- 應用程序測試
- 數據庫測試
- 模擬器
- 官方擴展包
- Cashier交易包
- Envoy 部署工具
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 附錄
- 集合
- 輔助函數
- 擴展包開發
- 交流說明