Sections

微型应用

Phalcon 提供一个非常 ‘轻’ 的应用,因此您可以用很少的的 PHP 代码创建 ‘Micro’ 应用。微应用程序,适合小的应用,这样会有很低的资源开销。

<?php

use Phalcon\Mvc\Micro;

$app = new Micro();

$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
);

$app->handle();

创建一个微型的应用程序

The Phalcon\Mvc\Micro class is the one responsible for creating a Micro application.

<?php

use Phalcon\Mvc\Micro;

$app = new Micro();

路由

Defining routes in a Phalcon\Mvc\Micro application is very easy. Routes are defined as follows:

   Application -> (method/verb) -> (route url/regex, callable PHP function)

设置

Routing is handled by the Phalcon\Mvc\Router object. [Info]

路由必须总是以 / 开头

通常情况下,起始应用程序中是路线 /,并在大多数情况下它通过获取 HTTP 方法访问:

<?php

// This is the start route
$app->get(
    '/',
    function () {
        echo '<h1>Welcome!</h1>';
    }
);

应用程序对象

Routes can be set using the Phalcon\Mvc\Micro application object as follows:

use Phalcon\Mvc\Micro;

$app = new Micro();

// Matches a GET request
$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
);

路由对象

You can also create a Phalcon\Mvc\Router object, setting the routes there and then injecting it in the dependency injection container.

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);

Setting up your routes using the Phalcon\Mvc\Micro applications verb methods (get, post, etc.) is much easier than setting up a router object with relevant routes and then injecting it in the application.

Each method has its advantages and disadvantages. It all depends on the design and needs of your application.

伪静态规则

让路由正常工作,需要在您的 web 服务器配置为特定的站点配置特定的选项。

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond   %{REQUEST_FILENAME} !-f
    RewriteRule   ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

处理程序

处理程序是代码的可调用段,得到附加到路由。 路由匹配匹配时,该处理程序执行已定义的所有参数。 处理程序是代码的任何可调用的 PHP 中存在。

定义

Phalcon offers several ways to attach a handler to a route. Your application needs and design as well as coding style will be the factors influencing your choice of implementation.

匿名函数

最后我们可以使用匿名函数 (如上图所示) 来处理该请求

$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
);

访问匿名函数内部的 $app 对象可以通过注射它,如下所示:

$app->get(
    '/orders/display/{name}',
    function ($name) use ($app) {
        $context = "<h1>This is order: {$name}!</h1>";
        $app->response->setContext($context);
        $app->response->send();
    }
);

函数

我们可以定义一个函数作为我们的处理程序并将其附加到 a 的特定路由。

// With a function
function order_display($name) {
    echo "<h1>This is order: {$name}!</h1>";
}

$app->get(
    '/orders/display/{name}',
    'orders_display'
);

静态方法

如下,我们也可以使用静态方法作为我们的处理程序:

class OrdersClass
{
    public static function display($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
}

$app->get(
    '/orders/display/{name}',
    'OrdersClass::display'
);

对象中的方法

我们还可以在对象中使用一种方法:

class OrdersClass
{
    public function display($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
}

$orders = new OrdersClass();
$app->get(
    '/orders/display/{name}',
    [
        $orders,
        'display',
    ]
);

控制器

With the Phalcon\Mvc\Micro you can create micro or medium applications. 中小型应用程序使用微体系结构,但扩大上它能利用更多微但小于完整的应用程序。

在中小型应用程序中,您可以组织中控制器的处理程序。

<?php

use Phalcon\Mvc\Micro\Collection as MicroCollection;

$orders = new MicroCollection();

// Set the main handler. ie。 a controller instance
$orders->setHandler(new OrdersController());

// Set a common prefix for all routes
$orders->setPrefix('/orders');

// Use the method 'index' in OrdersController
$orders->get('/', 'index');

// Use the method 'show' in OrdersController
$orders->get('/display/{slug}', 'show');

$app->mount($orders);

OrdersController 可能如下所示:

<?php

use Phalcon\Mvc\Controller;

class OrdersController extends Controller
{
    public function index()
    {
        // ...
    }

    public function show($name)
    {
        // ...
    }
}

Since our controllers extend the Phalcon\Mvc\Controller, all the dependency injection services are available with their respective registration names. For example:

<?php

use Phalcon\Mvc\Controller;

class OrdersController extends Controller
{
    public function index()
    {
        // ...
    }

    public function show($name)
    {
        $context = "<h1>This is order: {$name}!</h1>";
        $this->response->setContext($context);

        return $this->response;
    }
}

延迟加载

In order to increase performance, you might consider implementing lazy loading for your controllers (handlers). The controller will be loaded only if the relevant route is matched.

Lazy loading can be easily achieved when setting your handler in your Phalcon\Mvc\Micro\Collection:

$orders->setHandler('OrdersController', true);
$orders->setHandler('Blog\Controllers\OrdersController', true);

使用案例

我们正在开发一个 API 的在线商店。 终结点是 / 用户/ 订单/ 产品。 Each of those endpoints are registered using handlers, and each handler is a controller with relevant actions.

The controllers that we use as handlers are as follows:

<?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)
    {
        // ...
    }
}

We register the handlers:

<?php

use Phalcon\Mvc\Micro\Collection as MicroCollection;

// Users handler
$users = new MicroCollection();
$users->setHandler(new UsersController());
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);

// Orders handler
$orders = new MicroCollection();
$orders->setHandler(new OrdersController());
$orders->setPrefix('/users');
$orders->get('/get/{id}', 'get');
$orders->get('/add/{payload}', 'add');
$app->mount($orders);

// Products handler
$products = new MicroCollection();
$products->setHandler(new ProductsController());
$products->setPrefix('/products');
$products->get('/get/{id}', 'get');
$products->get('/add/{payload}', 'add');
$app->mount($products);

This implementation loads each handler in turn and mounts it in our application object. The issue with this approach is that each request will result to only one endpoint and therefore one class method executed. The remaining methods/handlers will just remain in memory without being used.

Using lazy loading we reduce the number of objects loaded in memory and as a result our application uses less memory.

The above implementation changes if we want to use lazy loading as follows:

<?php

use Phalcon\Mvc\Micro\Collection as MicroCollection;

// Users handler
$users = new MicroCollection();
$users->setHandler(new UsersController(), true);
$users->setPrefix('/users');
$users->get('/get/{id}', 'get');
$users->get('/add/{payload}', 'add');
$app->mount($users);

// Orders handler
$orders = new MicroCollection();
$orders->setHandler(new OrdersController(), true);
$orders->setPrefix('/users');
$orders->get('/get/{id}', 'get');
$orders->get('/add/{payload}', 'add');
$app->mount($orders);

// Products handler
$products = new MicroCollection();
$products->setHandler(new ProductsController(), true);
$products->setPrefix('/products');
$products->get('/get/{id}', 'get');
$products->get('/add/{payload}', 'add');
$app->mount($products);

Using this simple change in implementation, all handlers remain uninstantiated until requested by a caller. Therefore whenever a caller requests /orders/get/2, our application will instantiate the OrdersController and call the get method in it. Our application now uses less resources than before.

Not found (404)

Any route that has not been matched in our Phalcon\Mvc\Micro application will cause it to try and execute the handler defined with the notFound method. Similar to other methods/verbs (get, post etc.), you can register a handler in the notFound method which can be any callable PHP function.

<?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();
    }
);

You can also handle routes that have not been matched (404) with Middleware discussed below.

Methods - Verbs

The Phalcon\Mvc\Micro application provides a set of methods to bind the HTTP method with the route it is intended to.

delete

Matches if the HTTP method is DELETE and the route is /api/products/delete/{id}

    $app->delete(
        '/api/products/delete/{id}',
        'delete_product'
    );

get

Matches if the HTTP method is GET and the route is /api/products

    $app->get(
        '/api/products',
        'get_products'
    );

Matches if the HTTP method is HEAD and the route is /api/products

    $app->get(
        '/api/products',
        'get_products'
    );

map

Map allows you to attach the same endpoint to more than one HTTP method. The example below matches if the HTTP method is GET or POST and the route is /repos/store/refs

    $app
        ->map(
            '/repos/store/refs',
            'action_product'
        )
        ->via(
            [
                'GET',
                'POST',
            ]
        );

options

Matches if the HTTP method is OPTIONS and the route is /api/products/options

    $app->options(
        '/api/products/options',
        'info_product'
    );

patch

Matches if the HTTP method is PATCH and the route is /api/products/update/{id}

    $app->patch(
        '/api/products/update/{id}',
        'update_product'
    );

post

Matches if the HTTP method is POST and the route is /api/products/add

    $app->post(
        '/api/products',
        'add_product'
    );

put

Matches if the HTTP method is PUT and the route is /api/products/update/{id}

    $app->put(
        '/api/products/update/{id}',
        'update_product'
    );

Collections

Collections are a handy way to group collections attached to a handler and a common prefix (if needed). For a hypothetical /orders endpoint we could have the following endpoints:

/orders/get/{id}
/orders/add/{payload}
/orders/update/{id}
/orders/delete/{id}

All of those routes are handled by our OrdersController. We set up our routes with a collection as follows:

<?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);
The name that we bind each route has a suffix of Action. This is not necessary, your method can be called anything you like.

Parameters

We have briefly seen above how parameters are defined in the routes. Parameters are set in a route string by enclosing the name of the parameter in brackets.

$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
);

We can also enforce certain rules for each parameter by using regular expressions. The regular expression is set after the name of the parameter, separating it with :.

// Match the order id
$app->get(
    '/orders/display/{id:[0-9]+}',
    function ($id) {
        echo "<h1>This is order: #{$id}!</h1>";
    }
);

// Match a numeric (4) year and a title (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>';
    }
);

Additional information: Phalcon\Mvc\Router Info

Redirections

You can redirect one matched route to another using the Phalcon\Http\Response object, just like in a full application.

$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 we have to pass the $app object in our anonymous function to have access to the request object.

When using controllers as handlers, you can perform the redirect just as easy:

<?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function oldget($id)
    {
        return $this->response->redirect('users/get/' . $id);
    }

    public function get($id)
    {
        // ...
    }
}

Finally, you can perform redirections in your middleware (if you are using it). An example is below in the relevant section.

URLs for Routes

Another feature of the routes is setting up named routes and generating URLs for those routes. This is a two step process.

  • First we need to name our route. This can be achieved with the setName() method that is exposed from the methods/verbs in our application (get, post, etc.);
// Set a route with the name 'show-order'
$app
    ->get(
        '/orders/display/{id}',
        function ($id) use ($app) {
            // ... Find the order and show it
        }
    )
    ->setName('show-order');
  • We need to use the Phalcon\Mvc\Url component to generate URLs for the named routes.
// Use the named route and produce a URL from it
$app->get(
    '/',
    function () use ($app) {
        $url = sprintf(
            '<a href="%s">Show the order</a>',
            $app->url->get(
                [
                    'for' => 'show-order',
                    'id'  => 1234,
                ]
            )
        );

        echo $url;
    }
);

Dependency Injector

When a micro application is created, a Phalcon\Di\FactoryDefault services container is create implicitly.

<?php

use Phalcon\Mvc\Micro;
$app = new Micro();

$app->get(
    '/',
    function () use ($app) {
        $app->response->setContent('Hello!!');
        $app->response->send();
    }
);

You can also create a Di container yourself, and assign it to the micro application, therefore manipulating the services depending on the needs of your application.

<?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) {
        // Read a setting from the config
        echo $app->config->app_name;
    }
);

$app->post(
    '/contact',
    function () use ($app) {
        $app->flash->success('What are you doing Dave?');
    }
);

You can also use the array syntax to register services in the dependency injection container from the application object:

<br />&lt;?php

use Phalcon\Mvc\Micro;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlAdapter;

$app = new Micro();

// Setup the database service
$app['db'] = function () {
    return new MysqlAdapter(
        [
            'host'     =&gt; 'localhost',
            'username' =&gt; 'root',
            'password' =&gt; 'secret',
            'dbname'   =&gt; 'test_db',
        ]
    );
};

$app-&gt;get(
    '/blog',
    function () use ($app) {
        $news = $app['db']-&gt;query('SELECT * FROM news');

        foreach ($news as $new) {
            echo $new-&gt;title;
        }
    }
);

Responses

A micro application can return many different types of responses. Direct output, use a template engine, calculated data, view based data, JSON etc.

Handlers may return raw responses using plain text, Phalcon\Http\Response object or a custom built component that implements the Phalcon\Http\ResponseInterface.

Direct output

$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo "<h1>This is order: {$name}!</h1>";
    }
);

Including another file

$app->get(
    '/orders/display/{name}',
    function ($name) {
        require 'views/results.php';
    }
);

Direct output JSON

$app->get(
    '/orders/display/{name}',
    function ($name) {
        echo json_encode(
            [
                'code' => 200,
                'name' => $name,
            ]
        );
    }
);

New Response object

You can use the setContent method of the response object to return the response back:

$app->get(
    '/show/data',
    function () {
        // Create a response
        $response = new Phalcon\Http\Response();

        // Set the Content-Type header
        $response->setContentType('text/plain');

        // Pass the content of a file
        $response->setContent(file_get_contents('data.txt'));

        // Return the response
        return $response;
    }
);

Application Response

You can also use the Phalcon\Http\Response object to return responses to the caller. The response object has a lot of useful methods that make returning respones much easier.

$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');
    }
);

Return Application Response

A different approach returning data back to the caller is to return the response object directly from the application. When responses are returned by handlers they are automatically sent by the application.

<?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

JSON can be sent back just as easy using the Phalcon\Http\Response object:

$app->get(
    '/welcome/index',
    function () use ($app) {

        $data = [
            'code'    => 401,
            'status'  => 'error',
            'message' => 'Unauthorized access',
            'payload' => [],
        ];

        $response->setJsonContent($data);

        return $response;
    }
);

Events

A Phalcon\Mvc\Micro application works closely with a Phalcon\Events\Manager if it is present, to trigger events that can be used throughout our application. The type of those events is micro. These events trigger in our application and can be attached to relevant handlers that will perform actions needed by our application.

Available events

The following events are supported:

Event Name Triggered Can stop operation?
beforeHandleRoute Main method called; Routes have not been checked yet Yes
beforeExecuteRoute Route matched, Handler valid, Handler has not been executed yet Yes
afterExecuteRoute Handler just finished running No
beforeNotFound Route has not been found Yes
afterHandleRoute Route just finished executing Yes
afterBinding Triggered after models are bound but before executing the handler Yes

Authentication example

You can easily check whether a user has been authenticated or not using the beforeExecuteRoute event. In the following example, we explain how to control the application security using events:

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;

// Create a events manager
$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();

            // Return (false) stop the operation
            return false;
        }
    }
);

$app = new Micro();

// Bind the events manager to the app
$app->setEventsManager($eventsManager);

Not found example

You can easily check whether a user has been authenticated or not using the beforeExecuteRoute event. In the following example, we explain how to control the application security using events:

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;

// Create a events manager
$eventsManager = new EventsManager();

$eventsManager->attach(
    'micro:beforeNotFound',
    function (Event $event, $app) {
        $app->response->redirect('/404');
        $app->response->sendHeaders();

        return $app->response;
    }
);

$app = new Micro();

// Bind the events manager to the app
$app->setEventsManager($eventsManager);

Middleware

Middleware are classes that can be attached to your application and introduce another layer where business logic can exist. They run sequentially, according to the order they are registered and not only improve mainainability, by encapsulating specific functionality, but also performance. A middleware class can stop execution when a particular business rule has not been satisfied, thus allowing the application to exit early without executing the full cycle of a request.

The presence of a Phalcon\Events\Manager is essential for middleware to operate, so it has to be registered in our Di container.

Attached events

Middleware can be attached to a micro application in 3 different events. Those are:

Event Description
before Before the handler has been executed
after After the handler has been executed
final After the response has been sent to the caller
You can attach as many middleware classes as you want in each of the above events. They will be executed sequentially when the relevant event fires.

before

This event is perfect for stopping execution of the application if certain criteria is not met. In the below example we are checking if the user has been authenticated and stop execution with the necessary redirect.

<?php

$app = new Phalcon\Mvc\Micro();

// Executed before every route is executed
// Return false cancels the route execution
$app->before(
    function () use ($app) {
        if (false === $app['session']->get('auth')) {
            $app['flashSession']->error("The user isn't authenticated");

            $app['response']->redirect('/error');

            // Return false stops the normal execution
            return false;
        }

        return true;
    }
);

after

This event can be used to manipulate data or perform actions that are needed after the handler has finished executing. In the example below, we manipulate our response to send JSON back to the caller.

$app->map(
    '/api/robots',
    function () {
        return [
            'status' => 'OK',
        ];
    }
);

$app->after(
    function () use ($app) {
        // This is executed after the route is executed
        echo json_encode($app->getReturnedValue());
    }
);

finish

This even will fire up when the whole request cycle has been completed. In the example below, we use it to clean up some cache files.

$app->finish(
    function () use ($app) {
        if (true === file_exists('/tmp/processing.cache')) {
            unlink('/tmp/processing.cache');
        }
    }
);

设置

附加到您应用程序的中间件是很容易的如上所示,与 beforeafterfinish 的方法调用。

$app->before(
    function () use ($app) {
        if (false === $app['session']->get('auth')) {
            $app['flashSession']->error("The user isn't authenticated");

            $app['response']->redirect('/error');

            // Return false stops the normal execution
            return false;
        }

        return true;
    }
);

$app->after(
    function () use ($app) {
        // This is executed after the route is executed
        echo json_encode($app->getReturnedValue());
    }
);

将中间件附加到您的应用程序,如类和让它听事件中,从事件管理器可以实现,如下所示:

<?php

use Phalcon\Events\Manager;
use Phalcon\Mvc\Micro;

use Website\Middleware\CacheMiddleware;
use Website\Middleware\NotFoundMiddleware;
use Website\Middleware\ResponseMiddleware;

/**
 * Create a new Events Manager.
 */
$eventsManager = new Manager();
$application   = new Micro();

/**
 * Attach the middleware both to the events manager and the application
 */
$eventsManager->attach('micro', new CacheMiddleware());
$application->before(new CacheMiddleware());

$eventsManager->attach('micro', new NotFoundMiddleware());
$application->before(new NotFoundMiddleware());

/**
 * This one needs to listen on the `after` event
 */
$eventsManager->attach('micro', new ResponseMiddleware());
$application->after(new ResponseMiddleware());

/**
 * Make sure our events manager is in the DI container now
 */
$application->setEventsManager($eventsManager);

We need a Phalcon\Events\Manager object. 这可以是一个新实例化的对象或者我们可以得到那个存在在我们 DI 容器 (如果你使用了 FactoryDefault 人)。

We attach every middleware class in the micro hook in the Events Manager. We could also be a bit more specific and attach it to say the micro:beforeExecuteRoute event.

我们然后将中间件类附加在我们的应用程序上讨论以上 (before, after, finish) 的三个侦听事件之一。

Implementation

中间件可以是任何类型的 PHP 可调用函数。 您可以组织你的代码不管你喜欢它执行中间件。 If you choose to use classes for your middleware, you will need them to implement the Phalcon\Mvc\Micro\MiddlewareInterface

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;

/**
 * CacheMiddleware
 *
 * Caches pages to reduce processing
 */
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());

        // Check if the request is cached
        if ($cache->exists($key)) {
            echo $cache->get($key);

            return false;
        }

        return true;
    }
}

在中间件中的事件

The events that are triggered for our application also trigger inside a class that implements the Phalcon\Mvc\Micro\MiddlewareInterface. 这提供了极大的灵活性和力量开发商因为我们可以与请求流程进行交互。

API 的示例

假设我们有一个 API,我们已与微观应用程序。 我们将需要附加不同的中间件类在应用程序中,这样我们可以更好地控制应用程序的执行。

The middleware that we will use are:

  • Firewall
  • NotFound
  • Redirect
  • CORS
  • Request
  • Response

防火墙中间件

这个中间件被附加到我们微应用 before 事件。 这个中间件的目的是检查谁我们的 API 和基于白名单中,允许他们继续或不

<?php

use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;

/**
 * FirewallMiddleware
 *
 * Checks the whitelist and allows clients or not
 */
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;
    }
}

“找不到”的中间件

这个中间件进行处理时,这意味着请求 IP 允许访问我们的应用程序。 应用程序将尝试和匹配的路由,如果找不到 beforeNotFound 事件会火。 我们将停止处理然后发送回用户有关 404 响应。 这个中间件被附加到我们微应用 before 事件。

<?php

use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;

/**
 * NotFoundMiddleware
 *
 * Processes the 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

我们附加这个中间件再到我们的微应用程序 before 事件因为我们不想请求继续如果请求终结点需要被重定向。

<?php

use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\Micro\MiddlewareInterface;

/**
 * RedirectMiddleware
 *
 * Checks the request and redirects the user somewhere else if need be
 */
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 中间件

Again this middleware is attached to the before event of our Micro application. We need to ensure that it fires before anything happens with our application

<?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');
    }

    /**
     * Calls the middleware
     *
     * @param Micro $application
     *
     * @returns bool
     */
    public function call(Micro $application)
    {
        return true;
    }
}

请求中间件

This middleware is receiving a JSON payload and checks it. If the JSON payload is not valid it will stop execution.

<?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;
    }
}

响应中间件

这个中间件负责操纵我们的反应,并将其发送回调用方以 JSON 字符串。 因此我们需要将它附加到我们微应用 事件。

我们打算使用 call 方法这个中间件,因为我们有近执行整个请求周期。
<?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;
    }
}

模型

模型可以用于在微观应用中,只要我们指示应用程序如何去自动加载相关的类。

有关 db 服务必须在你 Di 容器注册。
<?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();

注入模型实例

By using the Phalcon\Mvc\Model\Binder class you can inject model instances into your routes:

<?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) {
        // do anything with $product object
    }
);

$app->handle();

既然联编程序对象内部使用反射 Api,可以是重,就设置一个缓存,加快这一进程的能力。 这可以通过使用 setModelBinder() 也可以接受服务名称第二个参数或只是通过向 Binder 构造函数传递一个缓存实例。

Currently the binder will only use the models primary key to perform a findFirst() on. An example route for the above would be /products/1.

视图

Phalcon\Mvc\Micro does not have inherently a view service. We can however use the Phalcon\Mvc\View\Simple component to render views.

<?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) {
        // Render app/views/products/show.phtml passing some variables
        echo $app['view']->render(
            'products/show',
            [
                'id'   => 100,
                'name' => 'Artichoke',
            ]
        );
    }
);
The above example uses the Phalcon\Mvc\View\Simple component, which uses relative paths instead of controllers and actions. You can use the Phalcon\Mvc\View component instead, but to do so you will need to change the parameters passed to render()
<?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) {
        // Render app/views/products/show.phtml passing some variables
        echo $app['view']->render(
            'products',
            'show',
            [
                'id'   => 100,
                'name' => 'Artichoke',
            ]
        );
    }
);

错误处理

The Phalcon\Mvc\Micro application also has an error method, which can be used to trap any errors that originate from exceptions. 下面的代码片段显示了此功能的基本用法:

<?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(),
            ]
        );
    }
);