中间件
Doctrine DBAL 支持中间件。根据 DBAL 文档
“中间件位于包装器组件和驱动程序之间”
它们允许装饰以下 DBAL 类
Doctrine\DBAL\Driver
Doctrine\DBAL\Driver\Connection
Doctrine\DBAL\Driver\Statement
Doctrine\DBAL\Driver\Result
例如,Symfony 使用中间件来收集当前页面执行的查询,并在分析器中提供它们。
你也可以创建你自己的中间件。这是一个(非常)简单的中间件示例,它可以防止使用 root 用户进行数据库连接。第一步是创建中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php
namespace App\Middleware;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Middleware;
class PreventRootConnectionMiddleware implements Middleware
{
public function wrap(Driver $driver): Driver
{
return new PreventRootConnectionDriver($driver);
}
}
正如你在 wrap
方法中看到的,中间件的原理是用你自己的对象来装饰 Doctrine 对象,这些对象带有你需要的逻辑。现在,驱动程序的 connect
方法必须在 PreventRootConnectionDriver
中进行装饰,以防止与 root 用户的连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<?php
namespace App\Middleware;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
use SensitiveParameter;
final class PreventRootConnectionDriver extends AbstractDriverMiddleware
{
public function connect(array $params): Connection
{
if (isset($params['user']) && $params['user'] === 'root') {
throw new \LogicException('Connecting to the database with the root user is not allowed.');
}
return parent::connect($params);
}
}
就是这样!与 root 用户的连接不再可能。请注意,connect
不是你可以在 Connection
中装饰的唯一方法。但是由于 AbstractDriverMiddleware
默认实现,你只需要装饰你想要添加一些逻辑的方法。要查看更高级的 Statement
类装饰示例,你可以查看 Symfony
类中开始的中间件实现。装饰 Result
类遵循相同的原则。
我们刚刚创建的中间件默认应用于所有连接。如果你的应用程序有多个 dbal 连接,你可以使用 AsMiddleware
PHP 属性将中间件范围限制为连接的子集。让我们将我们的中间件限制为名为 legacy
的连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<?php
namespace App\Middleware;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsMiddleware;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Middleware;
#[AsMiddleware(connections: ['legacy'])]
class PreventRootConnectionMiddleware implements Middleware
{
public function wrap(Driver $driver): Driver
{
return new PreventRootConnectionDriver($driver);
}
}
如果你在你的应用程序中注册了多个中间件,它们将按照注册的顺序执行。如果某些中间件需要先于另一个中间件执行,你可以通过 AsMiddleware
PHP 属性设置优先级。此优先级可以是任何整数,正数或负数。优先级越高,中间件执行得越早。如果未定义优先级,则优先级被视为 0。让我们确保我们的中间件是第一个执行的中间件,这样如果连接将被阻止,我们就不会设置调试或日志记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<?php
namespace App\Middleware;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsMiddleware;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Middleware;
#[AsMiddleware(priority: 10)]
class PreventRootConnectionMiddleware implements Middleware
{
public function wrap(Driver $driver): Driver
{
return new PreventRootConnectionDriver($driver);
}
}
priority
和 connections
可以一起使用,以将中间件限制为特定连接,同时更改其优先级。
上面呈现的所有示例都假设启用了 autoconfigure
。如果禁用 autoconfigure
,则必须将 doctrine.middleware
标签添加到中间件。此标签支持 connections
属性以限制中间件的范围,以及 priority
属性以更改已注册中间件的执行顺序。
注意
中间件是在 doctrine/dbal
的 3.2 版本中引入的,并且至少需要 doctrine/doctrine-bundle
的 2.6 版本才能像上面所示的那样在 Symfony 中集成它们。