超薄本推荐
Slim is a microframework that offers routing capabilities for easily creating small PHP applications. But an interesting, and powerful, feature is its concept of Middleware. Slim implements the Rack protocol, a pipelining architecture common to many Ruby frameworks. Thus, middleware can be written that wraps the application, and has access to and can affect the app’s environment and request and response objects in a chained manner.
Slim是一种微框架 ,具有路由功能,可轻松创建小型PHP应用程序。 但是中间件的概念是一个有趣且强大的功能。 Slim实现了Rack协议,这是许多Ruby框架共有的流水线架构。 因此,可以编写中间件来包装应用程序,并以链接的方式访问和影响应用程序的环境以及请求和响应对象。
I’ve found middleware to be an eloquent solution for implementing various filter-like services in a Slim app, such as authentication and caching. In this article I’ll explain how middleware works and share with you a simple cache example that highlights how you can implement your own custom middleware.
我发现中间件是一种在Slim应用程序中实现各种类似于过滤器的服务的雄辩解决方案,例如身份验证和缓存。 在本文中,我将解释中间件的工作原理,并与您分享一个简单的缓存示例,其中突出显示了如何实现自己的自定义中间件。
了解超薄中间件 (Understanding Slim Middleware)
The Slim documentation compares a Slim application to an onion, where each layer of the onion is middleware. This is an appropriate metaphor. To better understand it though, let’s assume we’re writing an application which makes use of authentication and caching. Our architecture might look like the following illustration:
Slim文档将Slim应用程序与洋葱进行比较,洋葱的每一层都是中间件。 这是一个适当的隐喻。 为了更好地理解它,让我们假设我们正在编写一个使用身份验证和缓存的应用程序。 我们的体系结构可能如下图所示:
The code that is responsible for generating the page’s content is wrapped in several layers of middleware, most importantly the authentication logic and caching logic.
负责生成页面内容的代码包装在多层中间件中,最重要的是身份验证逻辑和缓存逻辑。
The flow of execution passes through each layer and is either allowed to flow through to the next or is diverted. First a check is made to ensure the user is authenticated. If not, flow is interrupted and an HTTP 401 status is returned. Then a check is made to see if a cached copy of the content is available. If it is, flow is interrupted with a cached copy of the page being returned. Other layers of middleware might exist until the flow finally reaches the logic responsible for generating the page.
执行流经过每一层,或者被允许流向下一层,或者被转移。 首先,进行检查以确保用户通过身份验证。 如果不是,则流程中断并返回HTTP 401状态。 然后进行检查以查看内容的缓存副本是否可用。 如果是,则流程将被返回的页面的缓存副本中断。 在流最终到达负责生成页面的逻辑之前,可能会存在其他中间件层。
As our middleware methods return, the execution flow bubbles back up through them. The remaining logic of the caching middleware, for instance, would cache the page’s content for later look up.
当我们的中间件方法返回时,执行流会通过它们重新冒泡。 例如,缓存中间件的其余逻辑将缓存页面的内容以供以后查找。
实施中间件 (Implementing Middleware)
To see how one can goes about implementing custom middleware, let’s look at code that could serve as the caching middleware referenced above.
为了了解如何实现自定义中间件,让我们看一下可以用作上面引用的缓存中间件的代码。
The requirements for implementing any basic Slim middleware component is actually quite minimal. We only need to write a class that extends SlimMiddleware and override the call()
method. The middleware’s entry point is this call()
method, which we can either return from (thus interrupting the flow of execution) or call the next layer.
实际上,实现任何基本Slim中间件组件的要求都非常低。 我们只需要编写一个扩展SlimMiddleware并覆盖call()
方法的类。 中间件的入口点是此call()
方法,我们可以从中返回(从而中断执行流程)或调用下一层。
<?php
namespace MyMiddleware;
class Cache extends SlimMiddleware
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function call()
{
$key = $this->app->request()->getResourceUri();
$rsp = $this->app->response();
$data = $this->fetch($key);
if ($data) {
// cache hit... return the cached content
$rsp["Content-Type"] = $data["content_type"];
$rsp->body($data["body"]);
return;
}
// cache miss... continue on to generate the page
$this->next->call();
if ($rsp->status() == 200) {
// cache result for future look up
$this->save($key, $rsp["Content-Type"], $rsp->body());
}
}
protected function fetch($key)
{
$query = "SELECT content_type, body FROM cache
WHERE key = " . $this->db->quote($key);
$result = $this->db->query($query);
$row = $result->fetch(PDO::FETCH_ASSOC);
$result->closeCursor();
return $row;
}
protected function save($key, $contentType, $body)
{
$query = sprintf("INSERT INTO cache (key, content_type, body)
VALUES (%s, %s, %s)",
$this->db->quote($key),
$this->db->quote($contentType),
$this->db->quote($body)
);
$this->db->query($query);
}
}
The call()
method first checks whether the content is available in the cache. If it is, it sets the response’s Content-Type header and body and then returns, short-circuiting the pipeline. If there’s a cache miss, then $this->next->call()
is called to invoke the next middleware layer. When flow returns back to this point from the other middleware calls, a quick check is made on the request status and the relevant data is cached for future look ups.
call()
方法首先检查内容在缓存中是否可用。 如果是,它将设置响应的Content-Type标头和正文,然后返回,以使管道短路。 如果存在缓存未命中,则$this->next->call()
来调用下一个中间件层。 当流程从其他中间件调用返回到这一点时,将快速检查请求状态,并将相关数据缓存起来以备将来查找。
Because the class extends Slim’s Middleware
class, it has access to the Slim application’s instance through $this->app
, and thus indirectly access to the response and request objects. We can affect the response’s headers by treating it as an array, and the response’s body through it’s body()
method.
因为该类扩展了Slim的Middleware
类,所以它可以通过$this->app
访问Slim应用程序的实例,从而间接访问响应和请求对象。 我们可以通过将响应视为一个数组来影响响应的标头,并通过它的body()
方法将其视为响应的主体。
The fetch()
and save()
methods are protected helpers which simply wrap the database queries to look up and persist the content. I’ve included them here just to complete the example. It assumes a table cache
exists with the columns key
, content_type
, and body
. Your persistence mechanism may be different depending on your needs. Also, not shown here (for simplicity’s sake) is cache expiration, though it’s trivial to incorporate on your own.
fetch()
和save()
方法是受保护的帮助程序,它们仅包装数据库查询即可查找和保留内容。 我在这里包括它们只是为了完成示例。 假设存在具有key
, content_type
和body
的表cache
。 持久性机制可能会有所不同,具体取决于您的需求。 同样,这里没有显示(为简单起见)是缓存过期,尽管您可以自行合并。
注册和配置中间件 (Registering and Configuring Middleware)
Registering the middleware is done with Slim’s add()
method.
使用Slim的add()
方法完成中间件的注册。
<?php
require_once "../vendor/autoload.php";
$app = new SlimSlim();
$app->add(new MyMiddlewareCache($db));
Of course, more than one middleware can be registered by subsequent calls to add()
. Because new middleware surrounds any previously added middleware, this means they must be added in the reverse order that they’ll be called.
当然,可以通过随后对add()
调用来注册多个中间件。 因为新的中间件包围着任何先前添加的中间件,所以这意味着必须以相反的顺序添加它们。
<?php
$app = new SlimSlim();
$app->add(new MyMiddlewareCache($db));
$app->add(new MyMiddlewareAuth($db));
// ...
In the example above, the Cache middleware wraps the Slim app, and then Auth middleware wraps Cache. When $app->run()
is called, the flow of execution will resemble that in the illustration above, first entering the authentication middleware and working its way down to the route.
在上面的示例中,缓存中间件包装了Slim应用,然后Auth中间件包装了缓存。 调用$app->run()
,执行流程类似于上图中的流程,首先进入身份验证中间件,然后逐步进行处理。
Configuring middleware is generally done through the service’s constructor. In our example I’ve simply passed an active database connection so it can access the cache table, but you can write your class to accept whatever information you may need to customize its behavior. For example, the component could be re-written to accept a handler object that exposes a fetch()
and save()
method; this would allow us to remove the example methods (or use them as a default fallback), and the end-user developer would provide the functionality per their requirements as part of the component’s configuration.
配置中间件通常是通过服务的构造函数完成的。 在我们的示例中,我只是传递了一个活动数据库连接,以便它可以访问缓存表,但是您可以编写您的类以接受自定义其行为所需的任何信息。 例如,可以重写组件以接受处理程序对象,该处理程序对象公开了fetch()
和save()
方法; 这将允许我们删除示例方法(或将其用作默认后备),并且最终用户开发人员将根据其要求提供功能,作为组件配置的一部分。
结论 (Conclusion)
I’ve found middleware to be an eloquent solution for implementing various aspects of a Slim application. In this article I explained how the middleware architecture works and what’s necessary to implement your own middleware. There’s a small repository of extras with some basic middleware examples, such as CSRF protection and HTTP Authentication. I’ve refactored the example here and submitted a pull request, so if you write a useful middleware service, why not consider submitting it to the project so others can benefit as well?
我发现中间件是实现Slim应用程序各个方面的雄辩解决方案。 在本文中,我解释了中间件体系结构的工作原理以及实现自己的中间件的必要条件。 有一些附加的小型资源库,其中包含一些基本的中间件示例,例如CSRF保护和HTTP身份验证。 我在这里重构了示例并提交了pull请求 ,因此,如果您编写了有用的中间件服务,为什么不考虑将其提交给项目,以便其他人也能受益?
Image via Fotolia
图片来自Fotolia
翻译自: https://www.sitepoint.com/working-with-slim-middleware/
超薄本推荐