kod/bootstrap-slim

用于启动基于Slim框架的应用程序的库。

2.0.0 2019-09-11 13:42 UTC

This package is auto-updated.

Last update: 2024-09-12 01:14:57 UTC


README

此包提供启动Slim框架4应用程序的库。(版本1是为Slim 3设计的)

目的

  • 集中管理应用程序的初始化
  • 在单元测试中重用现有配置
  • 为单元测试动态创建新的定制配置
  • 优先使用use语句,减少require/include语句的使用

安装

将此包添加到composer.json文件的require部分

composer require kod/bootstrap-slim

3步实现

启动 - 第1步

index.php中处理公开请求。

<?php
use MyProject\Bootstrap;

// application configuration
$config = require('config.php');

 (new Bootstrap($config))
        ->addAppRoutes()
        ->addAppMiddlewares()
        ->run();

当然,Bootstrap类不提供任何路由或中间件,除了本地的Slim RoutingMiddleware和ErrorMiddleware。您需要扩展它,并在Bootstrap::addAppRoutes()中声明您的路由,以及在Bootstrap::addAppMiddlewares()方法中声明中间件堆栈。这可以通过以下示例中的类名声明轻松完成。

声明应用程序路由和中间件堆栈

<?php
namespace MyProject;

use Kod\BootstrapSlim\Bootstrap as SlimBootstrap;

class Bootstrap extends SlimBootstrap 
{
    public function addAppRoutes()
    {
        return $this->addRouteDefinitions(
            HomeRoutes::class,
            HelpRoutes::class
        );
    }
    public function addAppMiddleware()
    {
        return $this->addMiddleware(
            ValidateResponse::class,
            SecurityHeaders::class,
            ValidateRequest::class
        );
    }
}

这些类目前还不存在。所以,让我们从最重要的开始。让我们创建我们的路由。

路由 - 第2步

您有两种创建路由的方式。如果您喜欢面向对象编程,您可以通过扩展RouteDefinitions抽象类来创建一个包含您的路由的类,并在该类的__invoke($app)方法中声明您的路由。如上所述,您可以这样做,但您不是必须这样做。必须实施的是在您的类中实现__invoke($app)方法,该方法接收Slim\App实例作为参数。类的实例可以作为函数执行。

接下来是第二种选择。您可以将路由声明为接收Slim\App实例作为参数的闭包。第二种方法在需要动态创建路由的单元测试中非常有用。但我在说什么?我在过时。在PHP中,我们可以创建匿名类!¡Ay, caramba!

无论如何,请记住,在这两种情况下,都会将Slim\App实例作为参数传递。这意味着您可以将路由分组,并将中间件附加到某些路由或路由组。

作为类的路由

<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Kod\BootstrapSlim\RouteDefinitions;

class HomesRoutes extends RouteDefinitions
{
    public function __invoke($app)
    {
        $app->get('/', function (Request $request, Response $response, $args) {
            $response->getBody()->write('home page');

            return $response;
        });
    }
}

作为闭包声明的应用程序路由

<?php
namespace MyProject;

use Kod\BootstrapSlim\Bootstrap as SlimBootstrap;
use Slim\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use MyProject\Routes\HomesRoutes;

class Bootstrap extends SlimBootstrap 
{
    public function addAppRoutes()
    {
        return $this->addRouteDefinitions(
            HomesRoutes::class,
            function(App $app){
               $app->get('/', function (Request $request, Response $response, $args) {
                   return $response;
               });
            }
        );
    }
}

中间件 - 第3步

您可以通过两种方式创建中间件:作为一个类或一个闭包。要将其作为类创建,只需扩展可调用的Middleware抽象类,在其中实现您的业务逻辑,并在Middleware::__invoke(ServerRequestInterface $request, RequestHandlerInterface $handler)方法中触发其执行。

Slim 4中间件实现了PSR-15中间件接口,这意味着您不必使用Middleware抽象类,而是编写自己的实现,实现PSR-15中间件接口。这也可以做到。

无论如何,应用程序容器将由Slim\MiddlewareDispatcher推入中间件类的构造函数中。在Middleware派生类中,容器将存储在$this->ci属性中。

要作为闭包创建中间件,只需遵守函数签名。

作为可调用的类的中间件

<?php

use Kod\BootstrapSlim\Middleware;
use Psr\Http\{
    Message\ResponseInterface,
    Message\ServerRequestInterface,
};
use Psr\Http\Server\RequestHandlerInterface;

/**
 * MiddlewareMock writes some content before and after content generation.
 */
class MyMiddleware extends Middleware
{
    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     */
    public function __invoke(ServerRequestInterface  $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $container = $this->ci; // absolutely useless, just for the demo
        $response = $handler->handle($request);
        ... // some treatment here
        return $response;
    }
}

应用程序中间件声明

<?php
namespace MyProject;

use Kod\BootstrapSlim\Bootstrap as SlimBootstrap;
use Psr\Http\{
    Message\ResponseInterface,
    Message\ServerRequestInterface,
};
use Psr\Http\Server\RequestHandlerInterface;
use MyProject\Middleware\MyMiddleware;

class Bootstrap extends SlimBootstrap 
{
    public function addAppMiddleware()
    {
        return $this->addMiddleware(
            MyMiddleware::class,
            function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
                $container = $this; //bound by Slim\MiddlewareDispatcher
                $response = $handler->handle($request);
                ... // some treatment here
                return $response;
           }
        );
    }
}

路由/组中间件

Slim允许将中间件附加到路由或路由组。这可以在以下示例中的路由定义中完成。

<?php

use Kod\BootstrapSlim\RouteDefinitions;
use Slim\Psr7\{Request, Response};
use Slim\Interfaces\RouteCollectorProxyInterface;
use MyProject\Middleware\MyMiddleware;

class BillingRoutes extends RouteDefinitions
{
    /**
     * @param App $app
     */
    public function __invoke($app)
    {
        $app->group('/billing', function (RouteCollectorProxyInterface $group) {
            $group->get('/', function (Request $request, $response, $args) {
                // Route for /billing
                ... // some treatment
                return $response;
            });

            $group->get('/invoice/{id:[0-9]+}', function (Request $request, Response $response, $args) {
                // Route for /invoice/{id:[0-9]+}
                ... // some treatment
                return $response;
            });
        })->add(MyMiddleware::class);
    }
}

容器

Slim 4 引入了一个重大变更。它不再包含容器。但别担心!此包提供了一个基于 Pimple\ContainerContainerInterface 实现,其方法与 Slim 3 相同。如果你的应用程序依赖于其他容器实现,只需将你的容器实例提供给 Bootstrap。另一种自定义容器的办法是在你的 Bootstrap 类中覆盖 Bootstrap::init 方法,并在其中声明它。

<?php
use MyProject\Bootstrap;
use MyProject\MyContainer;

// application configuration
$config = require('config.php');
$container = new MyContainer($config);

(new Bootstrap($container))
        ->addAppRoutes()
        ->addAppMiddlewares()
        ->run();

单元测试

单元测试中的关键字是 UNIT。一旦你的应用程序组织良好且松耦合,单元测试就像用你的代码玩积木一样。你可以组装路由和中间件,按需声明它们。

<?php

use MyProject\{MyBootstrap, MyRoute};
use Kod\BootstrapSlim\Utils;

class MyRouteTest extends TestCase
{
    // test configuration
    public static $config = [ 'settings' => ['price' => 100] ];

    public function testMyRouteWithoutAppMiddleware()
    {
        // Prepare environment for the request
         Utils::setEnv([
            'REQUEST_METHOD' => 'GET',
            'REQUEST_URI' => '/',
         ]);
        // Process the request
        $response = (new MyBootstrap(static::$config))
            ->addRouteDefinitions(MyRoute::class)
            ->run(true);
       
        $content = (string)$response->getBody();
        // MyRoute class is supposed to return the price from settings  
        $this->assertContains(100, $content);
    }
    
    public function testMyRouteWithAppMiddleware()
    {
        // Prepare environment for the request
         Utils::setEnv([
            'REQUEST_METHOD' => 'GET',
            'REQUEST_URI' => '/',
         ]);
        // Process the request
        $response = (new MyBootstrap(static::$config))
            ->addAppMiddleware() // <- declare application middleware
            ->addRouteDefinitions(MyRoute::class)
            ->run(true);
       
        $content = (string)$response->getBody();
        // MyRoute class is supposed to return the price from settings  
        $this->assertContains(100, $content);
    }

}

Slim 依赖

由于最新版本引入了相当复杂的请求/响应伪造,Slim 框架 4 现在成为项目依赖的一部分。要摆脱这个依赖,并依赖于你的项目上安装的 slim 版本,你需要覆盖 Bootstrap::init 方法,并使用与你的项目一起提供的 AppFactoryServerRequestCreatorFactory