snootbeest / tantrum
基于 Slim 3 的 RESTful API 框架
Requires
- hassankhan/config: ^0.10.0
- monolog/monolog: ^1.23
- phpdocumentor/reflection-docblock: ^4.2
- psr/http-message: ^1.0
- psr/log: ^1.0
- psr/simple-cache: ^1.0
- slim/slim: ^3.8
- symfony/cache: ^4.0
Requires (Dev)
- mockery/mockery: ^1.0
- phpunit/phpunit: ^6.4
This package is not auto-updated.
Last update: 2024-09-19 01:32:30 UTC
README
Tantrum 是一个基于 Slim 3 框架的 RESTful API 框架。
它在多个方面扩展了 Slim 3
可配置服务
Tantrum 内置了一个基于配置和依赖注入的服务层。
要创建服务,只需创建一个实现了 SnootBeest\Tantrum\Service\ServiceProvider
接口和几行配置的类。
dependencies:
Psr\Log\LoggerInterface:
providerClass: MyProject\Namespace\LoggerProvider
dependencyType: default
dependencies:
- Doctrine\ORM\EntityManagerInterface
...
Doctrine\ORM\EntityManagerInterface
providerClass: MyProject\Namespace\EntityManagerProvider
...
configuration:
Doctrine\ORM\EntityManagerInterface
host: mysql
port: 3306
user: root
password:
...
这里我们看到配置的一部分,详细说明了依赖项(服务)。
该特定服务提供了一个 LoggerInterface
实例。 Psr\Log\LoggerInterface
是依赖注入容器中将使用的键。
使用完全限定的接口命名空间作为容器键 - 虽然不是必需的 - 提供了几个好处
- 消除歧义 - 您可以确切知道将返回什么
- 避免命名冲突 - 命名空间必须是唯一的
- 帮助实现构造函数注入 - 将容器键与类型提示的构造函数参数匹配非常酷。
providerClass
providerClass
是将被依赖注入容器调用的 ServiceProvider
,它最终将返回 LoggerInterface
实例。它包含所有实例化的逻辑。
dependencyType
dependencyType
键是可选的,并且可以有三个可能的值
- factory: 映射到 factory 方法 Pimple。每次调用都会返回一个新的实例。
- protect: 可预测地映射到 protect 方法 Pimple。如果您需要返回匿名函数,则非常有用。
- singleton: 这是 Pimple 的默认行为,如果您打算这样使用,则不需要包含依赖类型参数。
dependencies
依赖注入容器对于 ServiceProvider
不可用,以避免全局服务定位器反模式。因此,我们在此定义了一个子依赖项列表(完全限定命名空间的接口,希望如此!)!它们按定义的顺序注入到 ServiceProvider
构造函数中(这里没有反射)。在那里,它们可以提供给服务本身。
这意味着它们 必须 在应用程序的依赖项的其他地方定义,才能在容器中可用。
configuration
在上面的示例中,ORM 显然需要一个数据库连接,但这里没有提供这些详细信息。
在配置的不同部分,我们定义了依赖项的配置值,键再次是接口。
为什么不在依赖项旁边定义配置值?
依赖项通常比应用程序的配置更少动态。例如,您的应用程序始终需要其 LoggerInterface
实现,但数据库对每个环境都不同。此外,配置值可能在许多不同的服务之间共享和修改,最好将这些定义在其他地方。
路由检查
关于Slim 3,最令人满意的一点是能够快速将路由添加到应用程序中。这对于快速开发来说非常出色,但我在大型应用程序中发现,使用闭包添加路由很快就会变得难以控制。此外,单元测试闭包也相当困难。
Tantrum在构建过程中提供了路由检查(我通常在composer install
之后创建一个构建脚本)这种技术会在构建时反映路由并缓存结果,以便在运行时使用。以这种方式预先处理并存储路由允许进行构造函数注入,使得控制器易于测试,同时也给我们提供了将命名查询参数直接传递给路由方法的机会。
控制器配置在controllers
键下,它只是一个命名空间列表
...
controllers:
- Acme\Shop\Controllers\WidgetController
- Acme\Shop\Controllers\UserController
...
它要求你的控制器扩展一个小的类:SnootBeest\Tantrum\Controller
,并且你的控制器类应包含一些简单的注释以帮助路由器。让我们看看一个例子
<?php
namespace Acme\Shop;
use Snootbeest\Tantrum\Controller;
use Psr\Log\LoggerInterface;
class Widget extends Controller
{
/** @var LoggerInterface $logger */
private $logger;
/**
* Widget controller constructor
*/
public function __constructor(LoggerInterface $logger, int $requiredParameter, string $optionalParameter = 'some string')
{
$this->logger = $logger;
}
/**
* Gets a widget from the given widget id
*
* @httpMethod GET
* @httpMethod HEAD
* @pattern /widget/{:widgetId}
*/
public function getOneWidget(int $widgetId)
{
// Get and return the widget
$this->logger->debug(sprintf('Returning widget #%d', $widgetId));
}
...
}
这是我们的商店小部件控制器的示例。
构造函数注入
注意我们的__construct
方法有几个依赖项。你可以看到它需要一个Psr\Log\LoggerInterface
实例作为第一个参数。这是通过上面的过程配置的,并且会自动从依赖注入容器中提供。
第二个参数$requiredParameter
也是必需的,但没有类型提示。分发器会尝试从容器中获取它。如果没有找到,它将从配置中获取。如果仍然找不到,将抛出异常,导致返回500
响应。
第三个参数$optionalParameter
有一个默认值。如果其名称在容器或配置中找不到,将返回默认值。
我们还可以在路由声明中看到一些自定义注释。
@httpMethod
如果需要,可以提供多个@httpMethod注释。
@route
@route注释是Slim路由器需要解析请求到该方法的正则表达式。任何命名占位符都作为方法参数传递。请参阅https://slim.php.ac.cn/docs/objects/router.html#route-placeholders
当然,如果你需要利用Slim 3的更高级功能,你仍然可以在Slim 3文档中描述的方法中添加路由。我会随着时间的推移尝试添加更多的这些到路由检测中。