adeptoas/slim3-init

为 Slim 3 提供非常方便的支持库

v4.1.2 2023-09-26 12:50 UTC

README

这是一个围绕 Slim4 框架的非常方便的包装器,为我们提供了一些快捷方式和预填充的概念。

安装

将此添加到 composer.json

"require": {
	"adeptoas/slim3-init": "^4.0.0"
}

请确保合并您的 require-块!

使用

SlimInit

  • 创建一个 SlimInit 实例

     $app = new SlimInit();
  • 设置调试头

    如果请求中存在此头,则在使用默认异常处理器时将显示更多详细信息。设置为 null 以禁用此功能。

     setDebugHeader(?string $header, string $expectedValue = ''): SlimInit
  • 将异常映射到 HTTP 状态码

    在默认异常处理器中使用时,设置异常的 HTTP 状态码。

     setException(string $exception, int $statusCode): SlimInit
  • 将异常映射到异常处理器

    完全自定义异常处理。 $exceptionHandlerClass 必须是一个扩展 Adepto\Slim3Init\Handlers\ExceptionHandler 的类的完全限定名称。

     setException(string $exception, string $exceptionHandlerClass): SlimInit
  • 将多个异常映射到异常处理器或状态码

     setException(array $exceptions, int|string $statusCodeOrHandlerClass): SlimInit
  • 示例:添加错误收集服务如 Raygun、Sentry、…

    要向错误收集服务发送异常,请添加异常回调

     /** @var $app \Adepto\Slim3Init\SlimInit */
     $app->addExceptionCallback(function(\Adepto\Slim3Init\Request $request, Throwable $t) {
     	// Send $t to the service
     });

    或作为类

     class ExceptionCallback {
     	public function __invoke(\Adepto\Slim3Init\Request $request, Throwable $t) {
     		// Send $t to the service
     	}
     }
    
     /** @var $app \Adepto\Slim3Init\SlimInit */
     $app->addExceptionCallback(new ExceptionCallback());
  • 向容器中添加内容

     addToContainer(string $key, mixed $value): SlimInit
  • 添加单个处理器

    $className 必须是一个扩展 Adepto\Slim3Init\Handlers\Handler 的类的名称。

     addHandler(string $className): SlimInit
  • 从目录添加多个处理器

    添加特定目录中的所有处理器。非递归,文件名必须是类名后跟 .php

     addHandlersFromDirectory(string $dir): SlimInit
  • 添加与 Slim 4 兼容的中件

    有关中件的更多信息,请参阅 Slim 的文档。

     addMiddleware(callable $middleware): SlimInit
  • 运行!

    启动应用程序并监听传入请求。自动分配所有处理器并映射一切。

     run(): Slim\App

HandlerCaller

所有模拟方法返回会发送到浏览器的文本输出。这通常是 JSON 字符串。

  • 创建一个 HandlerCaller

    创建一个用于 $handlerClass 的调用者。您可以留空 $baseURL,但对于一致性和兼容性,您应该将其设置为此处理器将监听的基 URL(不带路由 URL)。

     $caller = new HandlerCaller(string $baseURL, string $handlerClass);
  • GET

    模拟带有 $headers$url 的 GET 请求。

     get(string $url, array $headers = []): string
  • POST

    模拟带有 $headers$url 的 POST 请求,并与其一起发送 $body。如果 $body 是数组,它将根据 $headers 中的 Content-Type 转换为表单或 JSON(默认为表单)。

     post(string $url, array $headers, mixed $body): string
  • PUT

    模拟带有 $headers$url 的 PUT 请求,并与其一起发送 $body$files。如果 $body 是数组,它将根据 $headers 中的 Content-Type 转换为表单或 JSON(默认为表单)。

     put(string $url, array $headers, mixed $body, array $files = []): string
  • PATCH

    与 POST 相同,只是 HTTP 方法为 PATCH 并带有 $files

     patch(string $url, array $headers, mixed $body, $files = []): string
  • DELETE

    与 POST 相同,只是 HTTP 方法为 DELETE。

     delete(string $url, array $headers, mixed $body): string

Handler

要使您的 API 做些事情,您需要创建扩展 Adepto\Slim3Init\Handlers\Handler 的处理器。每个处理器必须覆盖 getRoutes(): array 以返回一个路由数组。每个处理器默认通过构造函数接收一个容器。

您的处理器实际方法的签名必须如下

public function someName(Adepto\Slim3Init\Request $request, Adepto\Slim3Init\Response $response, \stdClass $args): Adepto\Slim3Init\Response

PrivilegedHandler

与 Handler 相同,只是此类型处理器还必须覆盖 actionAllowed(string $action, array $data = []): bool 以确定给定的操作是否允许和允许。PrivilegedHandler 有一个授权客户端(用于认证的客户端,Adepto\Slim3Init\Client\Client 的实例)通过 getClient()

forcePermission(string $action, array $data = []): bool

强制权限。这基本上就是actionAllowed(您必须重写)的一个别名,但如果不允许给定的权限,则抛出Adepto\Slim3Init\Exceptions\AccessDeniedException

路由

定义一个必须在您的处理器getRoutes()函数返回的数组中的路由。

new Route(string $httpMethod, string $url, string $classMethod, array $arguments = [], string $name = '')
  • $httpMethod:此路由使用的HTTP动词,即GET、POST、PATCH等。
  • $url:Slim兼容的URL模式,即/client/{client:[a-zA-Z0-9]+}
  • $classMethod:要调用处理器中的方法名称。
  • $arguments:要添加到方法$args的附加参数。
  • $name:路由名称,以便任何处理器都可以检索它。

接口:Client

  •  getUsername(): string

    应返回当前登录用户的用户名(如果使用了BasicAuth)。

  •  getPermissions(): array

    应返回一个包含Adepto\Slim3Init\Client\Permission对象的数组,用于当前登录用户(如果使用了BasicAuth)。

  •  hasPermission(string $name, array $data = []): bool;

    当当前登录用户具有特定权限时返回true。您可以使用$data将权限与更多信息结合,即当资源信息访问应限制为某些ID时。

接口:Permission

  •  getName(): string

    应返回权限的名称。您有权定义名称的外观。建议使用反向域名样式,即adepto.api.addKnowledge

  •  getData(): array

    应返回特定于该权限的信息,即可以访问的资源ID。如果没有任何信息,可以是空数组。

  •  isAllowed(): bool

    如果权限被允许,则返回true。

抽象:BasicAuth(中间件)

  •  authorize(array $credentials): array

    应返回一个包含更多信息以添加到容器的数组,例如用于与PrivilegedHandler一起使用的授权客户端。如果您要返回客户端,请确保将键设置为PrivilegedHandler::CONTAINER_CLIENT。如果用户无法授权,则抛出Adepto\Slim3Init\Exceptions\UnauthorizedException

示例

示例可在本存储库的examples/中找到。

从SlimInit 1.0升级(使用Slim3)

尽管Slim在底层发生了很大的变化,但SlimInit对SlimInit的实际影响尽可能小。有3个重大变更和几个小变更。

重大变更

1. 处理器现在必须返回Adepto\Slim3Init\Response的一个实例

以前,所有处理器都是使用仅Psr7兼容的接口定义的。虽然您仍然可以使用Psr7定义您处理器的参数,但返回值必须是Adepto\Slim3Init\Response的一个实例。如果您需要转换现有的响应,请使用Response::fromSlimResponse($originalResponse)

2. 中间件处理从回调$next()变为处理器

此变更直接来自Slim4,因为SlimInit没有改变此行为。以前,中间件是这样工作的

<?php
/* Slim3 */
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

class YourMiddleware {
	protected $container;

	public function __construct(ContainerInterface $container) {
		$this->container = $container;
	}

	public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Callable $next): ResponseInterface {
		// Something before others run
		$newResponse = $next($request, $response);
		// Code after others have run
		return $newResponse;
	}
}

现在,中间件使用RequestHandlerInterface来处理其他代码

<?php
/* Slim4 */
use Psr\Container\ContainerInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Adepto\Slim3Init\Request;

class YourMiddleware {
	protected $container;

	public function __construct(ContainerInterface $container) {
		$this->container = $container;
	}

	public function __invoke(Request $request, RequestHandlerInterface $handler): ResponseInterface {
		// Something before others run
		$response = $handler->handle($request);
		// Code after others have run
		return $response;
	}
}

您不再在运行其他中间件和处理器之前访问响应。

3. SlimInit不再包含handleErrorhandleNotFoundhandleMethodNotAllowed

现在,您不再在您的应用程序中覆盖这些方法来自定义500、404和405的处理,而是实现自己的ExceptionHandler并将其分配给异常。示例

<?php
use Adepto\Slim3Init\SlimInit;
use Adepto\Slim3Init\Request;
use Adepto\Slim3Init\Handlers\ExceptionHandler;
use Psr\Http\Message\ResponseInterface;

class NotFoundHandler extends ExceptionHandler {

	public function handle(Request $request, Throwable $t, bool $displayDetails): ResponseInterface {
		return $this->createResponse(404)
		            ->withJson(['error' => 'not_found']);
	}
}

// … your $app definition

/** @var $app SlimInit */
$app->setException(SomethingNotFoundException::class, NotFoundHandler::class);

您还可以覆盖现有的默认处理器404、405和500

use Adepto\Slim3Init\Exceptions\InternalErrorException;
use Adepto\Slim3Init\Exceptions\MethodNotAllowedException;
use Adepto\Slim3Init\Exceptions\NotFoundException;
use Adepto\Slim3Init\SlimInit;
/** @var $app SlimInit */

// Customize 404
$app->setException(NotFoundException::class, CustomHandler::class);
// Customize 405
$app->setException(MethodNotAllowedException::class, CustomHandler::class);
// Customize default handler (500)
$app->setException(InternalErrorException::class, CustomHandler::class);
// Customize all at once
$app->setException([
	NotFoundException::class,
	MethodNotAllowedException::class,
	InternalErrorException::class
], CustomHandler::class);

要使用默认异常处理器并仅自定义HTTP状态码,您可以继续分配状态码而不是处理器,就像在SlimInit 1.x中一样

use Adepto\Slim3Init\SlimInit;
// … your $app definition
/** @var $app SlimInit */
$app->setException(SomethingNotFoundException::class, 404);

4. SlimInit 4.1需要PHP 7.4+

SlimInit 4.1也是唯一针对PHP 7.4的版本。

5. SlimInit 4.2需要PHP 8.1+

目前处于开发中,此版本将需要PHP 8.1或更高版本。

小变更

1. SlimInit现在使用DI\Container的扩展

它仍然与Psr7 ContainerInterface兼容。如果您将Adepto\Slim3Init\Container指定为类型,可以无异常地使用ArrayAccess,如下所示

/** @var $container \Adepto\Slim3Init\Container */
// Get value like normal, with exception if key was not found
$value = $container->get('some-value');
// Get value array-style, with null being returned if key was not found
$value = $container['some-value'];

2. Slim的便捷方法withJSONwrite现在在Response上有一个自定义实现

为了成为地球上最通用的库,Slim的便捷方法在ResponseInterface上实现,而该接口没有这些方法,并且IDE可以正确识别它们,这是一个噩梦。因此,SlimInit包含了自己对这些方法的实现。

3. 新的抽象类Middleware

现在您还可以提供扩展Adepto\Slim3Init\Middleware\Middleware的中间件。这为您提供了某些便利,例如始终可以访问容器并创建响应。

use Adepto\Slim3Init\Middleware\Middleware;
use Adepto\Slim3Init\Request;
use Adepto\Slim3Init\Response;
use Psr\Http\Server\RequestHandlerInterface;

class YourMiddleware extends Middleware {

	public function __invoke(Request $request, RequestHandlerInterface $handler) : Response{
		return $this->createResponse(404);
	}
}

4. new HandlerCaller(…)已弃用

使用HandlerCaller::default(string $baseURL, string $handlerClass, $container = null)代替。

待续