[TOC]
# 微應用
Phalcon提供了一個非常“瘦”的應用程序,因此您可以使用最少的PHP代碼創建“Micro”應用程序。微應用程序適用于開銷非常低的小型應用程序。此類應用程序例如是我們的網站,我們的商城,API,原型等。
```php
<?php
use Phalcon\Mvc\Micro;
$app = new Micro();
$app->get(
'/orders/display/{name}',
function ($name) {
echo "<h1>This is order: {$name}!</h1>";
}
);
$app->handle();
```
## 建微應用
`Phalcon\Mvc\Micro`類是負責創建Micro應用程序的類。
```php
<?php
use Phalcon\Mvc\Micro;
$app = new Micro();
```
## 路由
在 `Phalcon\Mvc\Micro` 應用程序中定義路徑非常簡單。路由定義如下:
```text
Application -> (method/verb) -> (route url/regex, callable PHP function)
```
### 設置
路由由 `Phalcon\Mvc\Router`對象處理。
>[danger] 路由必須始終以`/`開頭
通常,應用程序中的起始路由是route `/`,在大多數情況下,它是通過GET HTTP方法訪問的:
```php
<?php
// 起始路由
$app->get(
'/',
function () {
echo '<h1>Welcome!</h1>';
}
);
```
#### 應用對象
可以使用 `Phalcon\Mvc\Micro` 應用程序對象設置路由,如下所示:
```php
use Phalcon\Mvc\Micro;
$app = new Micro();
// 匹配GET請求
$app->get(
'/orders/display/{name}',
function ($name) {
echo "<h1>This is order: {$name}!</h1>";
}
);
```
#### Router 對象
你也可以創建一個 `Phalcon\Mvc\Router` 對象,在那里設置路由,然后將其注入依賴注入容器中。
```php
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Router;
$router = new Router();
$router->addGet(
'/orders/display/{name}',
'OrdersClass::display';
}
);
$app = new Micro();
$app->setService('router', $router, true);
```
使用 `Phalcon\Mvc\Micro` 應用程序動詞方法(get,post等)設置路徑比設置具有相關路徑的路由器對象然后將其注入應用程序要容易得多。
每種方法都有其優點和缺點。這完全取決于您的應用程序的設計和需求。
### 重寫規則
為了使路由起作用,需要在Web服務器的特定站點配置中進行某些配置更改。
[Apache Rewrite Rules](http://httpd.apache.org/docs/current/rewrite/) 和 [NGINX Rewrite Rules](https://www.nginx.com/blog/creating-nginx-rewrite-rules/) 中概述了這些更改。
### 處理程序
處理程序是附加到路由的可調用代碼段。匹配路由時,將使用所有已定義的參數執行處理程序。處理程序是PHP中存在的任何可調用代碼段。
#### 定義
Phalcon提供了幾種將處理程序附加到路徑的方法。您的應用程序需求和設計以及編碼風格將是影響您選擇實施的因素。
##### 匿名函數
最后,我們可以使用匿名函數(如上所示)來處理請求
```php
$app->get(
'/orders/display/{name}',
function ($name) {
echo "<h1>This is order: {$name}!</h1>";
}
);
```
訪問匿名函數內的 `$app` 對象可以通過如下注入來實現:
```php
$app->get(
'/orders/display/{name}',
function ($name) use ($app) {
$content = "<h1>This is order: {$name}!</h1>";
$app->response->setContent($content);
$app->response->send();
}
);
```
##### 函數
我們可以將函數定義為處理程序并將其附加到特定路徑。
```php
// With a function
function order_display($name) {
echo "<h1>This is order: {$name}!</h1>";
}
$app->get(
'/orders/display/{name}',
'orders_display'
);
```
##### 靜態方法
我們也可以使用靜態方法作為我們的處理程序,如下所示:
```php
class OrdersClass
{
public static function display($name) {
echo "<h1>This is order: {$name}!</h1>";
}
}
$app->get(
'/orders/display/{name}',
'OrdersClass::display'
);
```
##### 對象方法
我們也可以在對象中使用一個方法:
```php
class OrdersClass
{
public function display($name) {
echo "<h1>This is order: {$name}!</h1>";
}
}
$orders = new OrdersClass();
$app->get(
'/orders/display/{name}',
[
$orders,
'display',
]
);
```
##### 控制器
使用 `Phalcon\Mvc\Micro` ,您可以創建微型或中型應用程序。中型應用程序使用微架構,但擴展它以使用超過Micro而不是Full應用程序。
在中型應用程序中,您可以在控制器中組織處理程
```php
<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;
$orders = new MicroCollection();
// 設置主處理程序。即。控制器實例
$orders->setHandler(new OrdersController());
// 為所有路由設置公共前綴
$orders->setPrefix('/orders');
// 在OrdersController中使用'index'方法
$orders->get('/', 'index');
// 在OrdersController中使用'show'方法
$orders->get('/display/{slug}', 'show');
$app->mount($orders);
```
`OrdersController` 可能如下所示:
```php
<?php
use Phalcon\Mvc\Controller;
class OrdersController extends Controller
{
public function index()
{
// ...
}
public function show($name)
{
// ...
}
}
```
由于我們的控制器擴展了 `Phalcon\Mvc\Controller`,因此所有依賴注入服務都具有各自的注冊名稱。例如:
```php
<?php
use Phalcon\Mvc\Controller;
class OrdersController extends Controller
{
public function index()
{
// ...
}
public function show($name)
{
$content = "<h1>This is order: {$name}!</h1>";
$this->response->setContent($content);
return $this->response;
}
}
```
#### 延遲加載
為了提高性能,您可以考慮為控制器(處理程序)實現延遲加載。僅當相關路線匹配時才會加載控制器。
在Phalcon\Mvc\Micro\Collection`中設置處理程序時,可以輕松實現延遲加載:
```php
$orders->setHandler('OrdersController', true);
$orders->setHandler('Blog\Controllers\OrdersController', true);
```
##### 用例
我們正在為在線商店開發API。端點是`/users`,`/orders`和`/products`。每個端點都使用處理程序注冊,每個處理程序都是具有相關操作的控制器。
我們用作處理程序的控制器如下:
```php
<?php
use Phalcon\Mvc\Controller;
class UsersController extends Controller
{
public function get($id)
{
// ...
}
public function add($payload)
{
// ...
}
}
class OrdersController extends Controller
{
public function get($id)
{
// ...
}
public function add($payload)
{
// ...
}
}
class ProductsController extends Controller
{
public function get($id)
{
// ...
}
public function add($payload)
{
// ...
}
}
```
我們注冊處理程序:
```php
<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;
// 用戶處理程序
$users = new MicroCollection();
$users->setHandler(new UsersController());
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);
// 訂單處理程序
$orders = new MicroCollection();
$orders->setHandler(new OrdersController());
$orders->setPrefix('/users');
$orders->get('/get/{id}', 'get');
$orders->get('/add/{payload}', 'add');
$app->mount($orders);
// 產品處理程序
$products = new MicroCollection();
$products->setHandler(new ProductsController());
$products->setPrefix('/products');
$products->get('/get/{id}', 'get');
$products->get('/add/{payload}', 'add');
$app->mount($products);
```
此實現依次加載每個處理程序并將其安裝在我們的應用程序對象中。這種方法的問題是每個請求只會導致一個端點,因此會執行一個類方法。其余的方法/處理程序將保留在內存中而不會被使用。
使用延遲加載我們減少了內存中加載的對象數量,因此我們的應用程序使用更少的內存。
如果我們想要使用延遲加載,上面的實現會改變如下:
```php
<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;
// 用戶處理程序
$users = new MicroCollection();
$users->setHandler('UsersController', true);
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);
// 訂單處理程序
$orders = new MicroCollection();
$orders->setHandler('OrdersController', true);
$orders->setPrefix('/users');
$orders->get('/get/{id}', 'get');
$orders->get('/add/{payload}', 'add');
$app->mount($orders);
// 產品處理程序
$products = new MicroCollection();
$products->setHandler('ProductsController', true);
$products->setPrefix('/products');
$products->get('/get/{id}', 'get');
$products->get('/add/{payload}', 'add');
$app->mount($products);
```
使用這種簡單的實現更改,所有處理程序在調用者請求之前都保持未實例化。因此,每當調用者請求`/orders/get/2`時,我們的應用程序將實例化`OrdersController`并在其中調用get方法。我們的應用現在使用的資源比以前少。
#### Not found (404)
在我們的`Phalcon\Mvc\Micro`應用程序中未匹配的任何路由將導致它嘗試執行使用`notFound`方法定義的處理程序。與其他方法/動詞(`get`,`post`等)類似,您可以在`notFound`方法中注冊一個處理程序,該方法可以是任何可調用的PHP函數。
```php
<?php
$app->notFound(
function () use ($app) {
$app->response->setStatusCode(404, 'Not Found');
$app->response->sendHeaders();
$message = 'Nothing to see here. Move along....';
$app->response->setContent($message);
$app->response->send();
}
);
```
您還可以處理未與下面討論的中間件匹配的路由(404)。
### 方法 - 動詞
`Phalcon\Mvc\Micro` 應用程序提供了一組方法來將HTTP方法與其預期的路由綁定。
#### delete
如果HTTP方法是 `DELETE` 且路由是 `/api/products/delete/{id}`,則匹配
```php
$app->delete(
'/api/products/delete/{id}',
'delete_product'
);
```
#### get
如果HTTP方法是 `GET` 且路由是 `/api/products`,則匹配
```php
$app->get(
'/api/products',
'get_products'
);
```
#### head
如果HTTP方法是 `HEAD` 且路由是 `/api/products`,則匹配
```php
$app->head(
'/api/products',
'get_products'
);
```
#### map
Map允許您將同一端點附加到多個HTTP方法。如果HTTP方法是`GET`或`POST`并且路由是`/repos/store/refs`,則下面的示例匹配
```php
$app
->map(
'/repos/store/refs',
'action_product'
)
->via(
[
'GET',
'POST',
]
);
```
#### options
如果HTTP方法是`OPTIONS` 且路由是 `/api/products/options`,則匹配
```php
$app->options(
'/api/products/options',
'info_product'
);
```
#### patch
如果HTTP方法是`PATCH` 且路由是 `/api/products/update/{id}`,則匹配
```php
$app->patch(
'/api/products/update/{id}',
'update_product'
);
```
#### post
如果HTTP方法是 `POST` 且路由是 `/api/products/add`,則匹配
```php
$app->post(
'/api/products',
'add_product'
);
```
#### put
如果HTTP方法是 `PUT` 且路由是 `/api/products/update/{id}`,則匹配
```php
$app->put(
'/api/products/update/{id}',
'update_product'
);
```
### 集合
集合是一種方便的方法,可以將附加到處理程序的集合和公共前綴(如果需要)分組。對于假設`/orders`端點,我們可以有以下端點:
/orders/get/{id}
/orders/add/{payload}
/orders/update/{id}
/orders/delete/{id}
所有這些路由都由`OrdersController`處理。我們使用如下集合設置路由:
```php
<?php
use Phalcon\Mvc\Micro\Collection as MicroCollection;
$orders = new MicroCollection();
$orders->setHandler(new OrdersController());
$orders->setPrefix('/orders');
$orders->get('/get/{id}', 'displayAction');
$orders->get('/add/{payload}', 'addAction');
$orders->get('/update/{id}', 'updateAction');
$orders->get('/delete/{id}', 'deleteAction');
$app->mount($orders);
```
>[warning] 我們綁定每個路由的名稱后綴為`Action`。 這不是必需的,您可以根據自己喜歡的方式調用方法。
### 參數
我們在上面簡要介紹了如何在路由中定義參數。通過將參數名稱括在括號中,可以在路徑字符串中設置參數。
```php
$app->get(
'/orders/display/{name}',
function ($name) {
echo "<h1>This is order: {$name}!</h1>";
}
);
```
我們還可以使用正則表達式為每個參數強制執行某些規則。正則表達式在參數名稱后面設置,用以下內容分隔 `:`
```php
// 匹配訂單id
$app->get(
'/orders/display/{id:[0-9]+}',
function ($id) {
echo "<h1>This is order: #{$id}!</h1>";
}
);
// 匹配數字(4)年和標題(alpha)
$app->get(
'/posts/{year:[0-9][4]}/{title:[a-zA-Z\-]+}',
function ($year, $title) {
echo '<h1>Title: $title</h1>';
echo '<h2>Year: $year</h2>';
}
);
```
附加信息:`Phalcon\Mvc\Router`
### 重定向
您可以使用 `Phalcon\Http\Response` 對象將一個匹配的路由重定向到另一個匹配的路由,就像在完整的應用程序中一樣。
```php
$app->post('/old/url',
function () use ($app) {
$app->response->redirect('new/url');
$app->response->sendHeaders();
}
);
$app->post('/new/welcome',
function () use ($app) {
echo 'This is the new Welcome';
}
);
```
**Note** 我們必須在匿名函數中傳遞`$app`對象才能訪問`request`對象。
使用控制器作為處理程序時,您可以輕松執行重定向:
```php
<?php
use Phalcon\Mvc\Controller;
class UsersController extends Controller
{
public function oldget($id)
{
return $this->response->redirect('users/get/' . $id);
}
public function get($id)
{
// ...
}
}
```
最后,您可以在中間件中執行重定向(如果您正在使用它)。以下是相關部分的示例。
### 路由的URL
路由的另一個特性是設置命名路由并為這些路由生成URL。這是一個兩步過程。
* 首先,我們需要命名我們的路由。這可以通過我們的應用程序中的方法/動詞公開的`setName()`方法來實現(`get`,`post`等);
```php
// 設置名為“show-order”的路由
$app
->get(
'/orders/display/{id}',
function ($id) use ($app) {
// ... 找到訂單并顯示它
}
)
->setName('show-order');
```
* 我們需要使用 `Phalcon\Mvc\Url` 組件為命名路由生成URL。
```php
// 使用指定的路由并從中生成URL
$app->get(
'/',
function () use ($app) {
$url = sprintf(
'<a href="%s">Show the order</a>',
$app->url->get(
[
'for' => 'show-order',
'id' => 1234,
]
)
);
echo $url;
}
);
```
## 依賴注入
創建微應用程序時,將隱式創建 `Phalcon\Di\FactoryDefault` 服務容器。
```php
<?php
use Phalcon\Mvc\Micro;
$app = new Micro();
$app->get(
'/',
function () use ($app) {
$app->response->setContent('Hello!!');
$app->response->send();
}
);
```
您也可以自己創建Di容器,并將其分配給微應用程序,從而根據應用程序的需要操作服務。
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Di\FactoryDefault;
use Phalcon\Config\Adapter\Ini as IniConfig;
$di = new FactoryDefault();
$di->set(
'config',
function () {
return new IniConfig('config.ini');
}
);
$app = new Micro();
$app->setDI($di);
$app->get(
'/',
function () use ($app) {
// 從配置中讀取設置
echo $app->config->app_name;
}
);
$app->post(
'/contact',
function () use ($app) {
$app->flash->success('What are you doing Dave?');
}
);
```
您還可以使用數組語法從應用程序對象注冊依賴項注入容器中的服務:
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlAdapter;
$app = new Micro();
// 設置數據庫服務
$app['db'] = function () {
return new MysqlAdapter(
[
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'dbname' => 'test_db',
]
);
};
$app->get(
'/blog',
function () use ($app) {
$news = $app['db']->query('SELECT * FROM news');
foreach ($news as $new) {
echo $new->title;
}
}
);
```
## 響應
微應用程序可以返回許多不同類型的響應。直接輸出,使用模板引擎,計算數據,基于視圖的數據,JSON等。
處理程序可以使用純文本,`Phalcon\Http\Response` 對象或實現 `Phalcon\Http\ResponseInterface`的自定義構建組件返回原始響應。
### 直接輸出
```php
$app->get(
'/orders/display/{name}',
function ($name) {
echo "<h1>This is order: {$name}!</h1>";
}
);
```
### 包含另一個文件
```php
$app->get(
'/orders/display/{name}',
function ($name) {
require 'views/results.php';
}
);
```
### 直接輸出JSON
```php
$app->get(
'/orders/display/{name}',
function ($name) {
echo json_encode(
[
'code' => 200,
'name' => $name,
]
);
}
);
```
### 新的Response對象
您可以使用Response對象的setContent方法返回響應:
```php
$app->get(
'/show/data',
function () {
// 創建一個響應
$response = new Phalcon\Http\Response();
// 設置Content-Type標頭
$response->setContentType('text/plain');
// 傳遞文件的內容
$response->setContent(file_get_contents('data.txt'));
// 返回響應
return $response;
}
);
```
### 應用響應
您還可以使用 `Phalcon\Http\Response` 對象將響應返回給調用者。Response對象有許多有用的方法,使返回響應更容易。
```php
$app->get(
'/show/data',
function () use ($app) {
// Set the Content-Type header
$app->response->setContentType('text/plain');
$app->response->sendHeaders();
// Print a file
readfile('data.txt');
}
);
```
### 返回應用響應
將數據返回給調用者的另一種方法是直接從應用程序返回Response對象。當處理程序返回響應時,它們將由應用程序自動發送。
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Http\Response;
$app = new Micro();
// Return a response
$app->get(
'/welcome/index',
function () {
$response = new Response();
$response->setStatusCode(401, 'Unauthorized');
$response->setContent('Access is not authorized');
return $response;
}
);
```
### JSON
使用 `Phalcon\Http\Response` 對象可以輕松地發回JSON:
```php
$app->get(
'/welcome/index',
function () use ($app) {
$data = [
'code' => 401,
'status' => 'error',
'message' => 'Unauthorized access',
'payload' => [],
];
$response->setJsonContent($data);
return $response;
}
);
```
## 事件
`Phalcon\Mvc\Micro` 應用程序與 `Phalcon\Events\Manager` 密切配合(如果存在),以觸發可在整個應用程序中使用的事件。這些事件的類型是微觀的。這些事件在我們的應用程序中觸發,并且可以附加到將執行我們的應用程序所需的操作的相關處理程序。
### 可用事件
支持以下事件:
| 事件名稱 | Triggered | Can stop operation? |
| ------------------ | ---------------------------------------- | :-----------------: |
| beforeHandleRoute | Main 方法調用;路由尚未檢查 | Yes |
| beforeExecuteRoute | 路由匹配,處理程序有效,處理程序尚未執行 | Yes |
| afterExecuteRoute | 處理程序剛剛運行完畢 | No |
| beforeNotFound | 尚未找到路由 | Yes |
| afterHandleRoute | 路由剛剛執行結束 | Yes |
| afterBinding | 在綁定模型之后但在執行處理程序之前觸發 | Yes |
#### 驗證示例
您可以使用`beforeExecuteRoute`事件輕松檢查用戶是否已經過身份驗證。在以下示例中,我們將介紹如何使用事件控制應用程序安全性:
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
// 創建一個事件管理器
$eventsManager = new EventsManager();
$eventsManager->attach(
'micro:beforeExecuteRoute',
function (Event $event, $app) {
if ($app->session->get('auth') === false) {
$app->flashSession->error("The user isn't authenticated");
$app->response->redirect('/');
$app->response->sendHeaders();
// 返回(false)停止操作
return false;
}
}
);
$app = new Micro();
// 將事件管理器綁定到應用程序
$app->setEventsManager($eventsManager);
```
#### Not found 示例
您可以訂閱以實現業務邏輯的另一個內置事件是`beforeNotFound`。以下示例顯示了處理不存在的地址請求的方法之一:
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
// 創建一個事件管理器
$eventsManager = new EventsManager();
$eventsManager->attach(
'micro:beforeNotFound',
function (Event $event, $app) {
$app->response->redirect('/404');
$app->response->sendHeaders();
return $app->response;
}
);
$app = new Micro();
// 將事件管理器綁定到應用程序
$app->setEventsManager($eventsManager);
```
## 中間件
中間件是可以附加到應用程序的類,并引入了可以存在業務邏輯的另一個層。它們按照它們注冊的順序依次運行,不僅通過封裝特定功能而且還提高了性能,從而提高了可維護性。中間件類可以在未滿足特定業務規則時停止執行,從而允許應用程序提前退出而不執行請求的完整周期。
`Phalcon\Events\Manager` 的存在對于中間件的運行至關重要,因此必須在我們的Di容器中注冊。
### 附加事件
中間件可以在3個不同的事件中附加到微應用程序。那些是:
| 事件 | 描述 |
| ------ | ------------------ |
| before | 在處理程序執行之前 |
| after | 處理程序執行完畢后 |
| final | 響應發送給調用者后 |
>[warning] 您可以在上述每個事件中附加任意數量的中間件類。 當相關事件觸發時,它們將按順序執行。
#### before
如果不滿足某些條件,此事件非常適合停止執行應用程序。在下面的示例中,我們檢查用戶是否已經過身份驗證,并使用必要的重定向停止執行。
```php
<?php
$app = new Phalcon\Mvc\Micro();
// 在執行每個路由之前執行
// 返回false取消路由執行
$app->before(
function () use ($app) {
if (false === $app['session']->get('auth')) {
$app['flashSession']->error("The user isn't authenticated");
$app['response']->redirect('/error');
// 返回false會停止正常執行
return false;
}
return true;
}
);
```
#### after
此事件可用于操作數據或執行處理程序執行完畢后所需的操作。在下面的示例中,我們操縱響應以將JSON發送回調用者。
```php
$app->map(
'/api/robots',
function () {
return [
'status' => 'OK',
];
}
);
$app->after(
function () use ($app) {
// 這是在執行路由后執行的
echo json_encode($app->getReturnedValue());
}
);
```
#### finish
當整個請求周期完成時,這甚至會啟動。在下面的示例中,我們使用它來清理一些緩存文件。
```php
$app->finish(
function () use ($app) {
if (true === file_exists('/tmp/processing.cache')) {
unlink('/tmp/processing.cache');
}
}
);
```
### 設置
如上所示,使用`before`,`after`和`finish`方法調用將中間件附加到應用程序非常簡單。
```php
$app->before(
function () use ($app) {
if (false === $app['session']->get('auth')) {
$app['flashSession']->error("The user isn't authenticated");
$app['response']->redirect('/error');
// 返回false會停止正常執行
return false;
}
return true;
}
);
$app->after(
function () use ($app) {
// 這是在執行路由后執行的
echo json_encode($app->getReturnedValue());
}
);
```
將中間件作為類附加到應用程序并讓它監聽事件管理器中的事件可以實現如下:
```php
<?php
use Phalcon\Events\Manager;
use Phalcon\Mvc\Micro;
use Website\Middleware\CacheMiddleware;
use Website\Middleware\NotFoundMiddleware;
use Website\Middleware\ResponseMiddleware;
/**
* 創建一個新的事件管理器。
*/
$eventsManager = new Manager();
$application = new Micro();
/**
* 將中間件附加到事件管理器和應用程序
*/
$eventsManager->attach('micro', new CacheMiddleware());
$application->before(new CacheMiddleware());
$eventsManager->attach('micro', new NotFoundMiddleware());
$application->before(new NotFoundMiddleware());
/**
* 這個人需要聽'after`事件
*/
$eventsManager->attach('micro', new ResponseMiddleware());
$application->after(new ResponseMiddleware());
/**
* 確保我們的事件管理器現在位于DI容器中
*/
$application->setEventsManager($eventsManager);
```
我們需要一個`Phalcon\Events\Manager` 對象。這可以是一個新實例化的對象,或者我們可以獲取DI容器中存在的對象(如果您使用了FactoryDefault `FactoryDefault`對象)。
我們在事件管理器中的`微應用`鉤子中附加每個中間件類。我們也可以更具體一點,并附上它來說明:`beforeExecuteRoute`事件。
然后,我們將應用程序中的中間件類附加到上面討論的三個偵聽事件之一(`before`, `after`, `finish`)。
### 履行
中間件可以是任何類型的PHP可調用函數。您可以按照自己喜歡的方式組織代碼來實現中間件。如果您選擇使用中間件類,則需要它們來實現`Phalcon\Mvc\Micro\MiddlewareInterface`
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* CacheMiddleware
*
* 緩存頁面以減少處理
*/
class CacheMiddleware implements MiddlewareInterface
{
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
$cache = $application['cache'];
$router = $application['router'];
$key = preg_replace('/^[a-zA-Z0-9]/', '', $router->getRewriteUri());
// 檢查請求是否已緩存
if ($cache->exists($key)) {
echo $cache->get($key);
return false;
}
return true;
}
}
```
### 中間件中的事件
為我們的應用程序觸發的事件也會在實現`Phalcon\Mvc\Micro\MiddlewareInterface`的類中觸發。這為開發人員提供了極大的靈活性和功能,因為我們可以與請求流程進行交互
#### API示例
假設我們已經使用Micro應用程序實現了API。我們需要在應用程序中附加不同的中間件類,以便我們可以更好地控制應用程序的執行。
我們將使用的中間件是:
* Firewall
* NotFound
* Redirect
* CORS
* Request
* Response
##### Firewall Middleware
此中間件附加到Micro應用程序的`before`事件。此中間件的目的是檢查誰在調用我們的API并基于白名單,允許它們繼續或不繼續
```php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* FirewallMiddleware
*
* 檢查白名單并允許客戶端與否
*/
class FirewallMiddleware implements MiddlewareInterface
{
/**
* Before anything happens
*
* @param Event $event
* @param Micro $application
*
* @returns bool
*/
public function beforeHandleRoute(Event $event, Micro $application)
{
$whitelist = [
'10.4.6.1',
'10.4.6.2',
'10.4.6.3',
'10.4.6.4',
];
$ipAddress = $application->request->getClientAddress();
if (true !== array_key_exists($ipAddress, $whitelist)) {
$this->response->redirect('/401');
$this->response->send();
return false;
}
return true;
}
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
return true;
}
}
```
##### Not Found Middleware
處理此中間件時,這意味著允許請求IP訪問我們的應用程序。應用程序將嘗試匹配路由,如果沒有找到,則會觸發 `beforeNotFound`事件。我們將停止處理,然后向用戶發回相關的404響應。此中間件附加到Micro應用程序的`before`事件
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* NotFoundMiddleware
*
* 處理404s
*/
class NotFoundMiddleware implements MiddlewareInterface
{
/**
* The route has not been found
*
* @returns bool
*/
public function beforeNotFound()
{
$this->response->redirect('/404');
$this->response->send();
return false;
}
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
return true;
}
}
```
##### Redirect Middleware
我們將此中間件再次附加到Micro應用程序的`before`事件,因為如果需要重定向請求的端點,我們不希望請求繼續。
```php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* RedirectMiddleware
*
* 檢查請求并在需要時將用戶重定向到其他位置
*/
class RedirectMiddleware implements MiddlewareInterface
{
/**
* Before anything happens
*
* @param Event $event
* @param Micro $application
*
* @returns bool
*/
public function beforeHandleRoute(Event $event, Micro $application)
{
if ('github' === $application->request->getURI()) {
$application->response->redirect('https://github.com');
$application->response->send();
return false;
}
return true;
}
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
return true;
}
}
```
##### CORS Middleware
此中間件再次附加到Micro應用程序的`before`事件。我們需要確保它在我們的應用程序發生任何事情之前觸發
```php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* CORSMiddleware
*
* CORS checking
*/
class CORSMiddleware implements MiddlewareInterface
{
/**
* Before anything happens
*
* @param Event $event
* @param Micro $application
*
* @returns bool
*/
public function beforeHandleRoute(Event $event, Micro $application)
{
if ($application->request->getHeader('ORIGIN')) {
$origin = $application->request->getHeader('ORIGIN');
} else {
$origin = '*';
}
$application
->response
->setHeader('Access-Control-Allow-Origin', $origin)
->setHeader(
'Access-Control-Allow-Methods',
'GET,PUT,POST,DELETE,OPTIONS'
)
->setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Range, ' .
'Content-Disposition, Content-Type, Authorization'
)
->setHeader('Access-Control-Allow-Credentials', 'true');
return true;
}
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
return true;
}
}
```
##### Request Middleware
此中間件正在接收JSON有效負載并對其進行檢查。如果JSON有效負載無效,它將停止執行。
```php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* RequestMiddleware
*
* Check incoming payload
*/
class RequestMiddleware implements MiddlewareInterface
{
/**
* Before the route is executed
*
* @param Event $event
* @param Micro $application
*
* @returns bool
*/
public function beforeExecuteRoute(Event $event, Micro $application)
{
json_decode($application->request->getRawBody());
if (JSON_ERROR_NONE !== json_last_error()) {
$application->response->redirect('/malformed');
$application->response->send();
return false;
}
return true;
}
/**
* Calls the middleware
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
return true;
}
}
```
##### Response Middleware
該中間件負責操作我們的響應并將其作為JSON字符串發送回調用者。因此,我們需要將它附加到Micro應用程序的`after`事件。
>[warning] 我們將對此中間件使用`call`方法,因為我們幾乎執行了整個請求周期。
```php
<?php
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;
/**
* ResponseMiddleware
*
* Manipulates the response
*/
class ResponseMiddleware implements MiddlewareInterface
{
/**
* Before anything happens
*
* @param Micro $application
*
* @returns bool
*/
public function call(Micro $application)
{
$payload = [
'code' => 200,
'status' => 'success',
'message' => '',
'payload' => $application->getReturnedValue(),
];
$application->response->setJsonContent($payload);
$application->response->send();
return true;
}
}
```
## 模型
模型可以在Micro應用程序中使用,只要我們指示應用程序如何使用自動加載器找到相關的類。
>[warning] 必須在Di容器中注冊相關的`db`服務。
```php
<?php
$loader = new \Phalcon\Loader();
$loader
->registerDirs(
[
__DIR__ . '/models/',
]
)
->register();
$app = new \Phalcon\Mvc\Micro();
$app->get(
'/products/find',
function () {
$products = \MyModels\Products::find();
foreach ($products as $product) {
echo $product->name, '<br>';
}
}
);
$app->handle();
```
## 注入模型實例
通過使用 `Phalcon\Mvc\Model\Binder` 類,您可以將模型實例注入到路徑中:
```php
<?php
$loader = new \Phalcon\Loader();
$loader->registerDirs(
[
__DIR__ . '/models/',
]
)->register();
$app = new \Phalcon\Mvc\Micro();
$app->setModelBinder(new \Phalcon\Mvc\Model\Binder());
$app->get(
"/products/{product:[0-9]+}",
function (Products $product) {
// 用$product對象做任何事情
}
);
$app->handle();
```
由于`Binder`對象使用的內部Reflection Api很重,因此可以設置緩存以加快進程。這可以通過使用`setModelBinder()`的第二個參數來完成,該參數也可以接受服務名稱或僅通過將緩存實例傳遞給`Binder`構造函數。
目前,構建器僅使用模型主鍵來執行 `findFirst()` 。上面的示例路由是 `/products/1`。
## Views
`Phalcon\Mvc\Micro` 本身并不具有視圖服務。但是我們可以使用`Phalcon\Mvc\View\Simple` 組件來呈現視圖。
```php
<?php
$app = new Phalcon\Mvc\Micro();
$app['view'] = function () {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('app/views/');
return $view;
};
// Return a rendered view
$app->get(
'/products/show',
function () use ($app) {
// 渲染app/views /products/ show.phtml傳遞一些變量
echo $app['view']->render(
'products/show',
[
'id' => 100,
'name' => 'Artichoke',
]
);
}
);
```
>[warning] 上面的示例使用` Phalcon\Mvc\View\Simple`組件,該組件使用相對路徑而不是控制器和操作。 您可以使用`Phalcon\Mvc\View`組件,但為此,您需要更改傳遞給的參數`render()`
```php
<?php
$app = new Phalcon\Mvc\Micro();
$app['view'] = function () {
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('app/views/');
return $view;
};
// Return a rendered view
$app->get(
'/products/show',
function () use ($app) {
// 渲染app/views /products/ show.phtml傳遞一些變量
echo $app['view']->start()->render(
'products',
'show',
[
'id' => 100,
'name' => 'Artichoke',
]
)->finish()->getContent();
}
);
```
## 錯誤處理
`Phalcon\Mvc\Micro` 應用程序還有一個`error`方法,可用于捕獲源自異常的任何錯誤。以下代碼段顯示了此功能的基本用法:
```php
<?php
$app = new Phalcon\Mvc\Micro();
$app->get(
'/',
function () {
throw new \Exception('Some error happened', 401);
}
);
$app->error(
function ($exception) {
echo json_encode(
[
'code' => $exception->getCode(),
'status' => 'error',
'message' => $exception->getMessage(),
]
);
}
);
```
- 常規
- Welcome
- 貢獻
- 生成回溯
- 測試重現
- 單元測試
- 入門
- 安裝
- Web服務器設置
- WAMP
- XAMPP
- 教程
- 基礎教程
- 教程:創建一個簡單的REST API
- 教程:V?kuró
- 提升性能
- 教程:INVO
- 開發環境
- Phalcon Compose (Docker)
- Nanobox
- Phalcon Box (Vagrant)
- 開發工具
- Phalcon開發者工具的安裝
- Phalcon開發者工具的使用
- 調試應用程序
- 核心
- MVC應用
- 微應用
- 創建命令行(CLI)應用程序
- 依賴注入與服務定位
- MVC架構
- 服務
- 使用緩存提高性能
- 讀取配置
- 上下文轉義
- 類加載器
- 使用命名空間
- 日志
- 隊列
- 數據庫
- 數據庫抽象層
- Phalcon查詢語言(PHQL)
- ODM(對象文檔映射器)
- 使用模型
- 模型行為
- ORM緩存
- 模型事件
- 模型元數據
- 模型關系
- 模型事務
- 驗證模型
- 數據庫遷移
- 分頁
- 前端
- Assets管理
- 閃存消息
- 表單
- 圖像
- 視圖助手(標簽)
- 使用視圖
- Volt:模板引擎
- 業務邏輯
- 訪問控制列表(ACL)
- 注解解析器
- 控制器
- 調度控制器
- 事件管理器
- 過濾與清理
- 路由
- 在session中存儲數據
- 生成URL和路徑
- 驗證
- HTTP
- Cookies管理
- 請求環境
- 返回響應
- 安全
- 加密/解密
- 安全
- 國際化
- 國際化
- 多語言支持