跳到内容

中间件

编辑此页

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\Bridge\Doctrine\Middleware\Debug\Middleware 类中开始的中间件实现。装饰 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);
    }
}

priorityconnections 可以一起使用,以将中间件限制为特定连接,同时更改其优先级。

上面呈现的所有示例都假设启用了 autoconfigure。如果禁用 autoconfigure,则必须将 doctrine.middleware 标签添加到中间件。此标签支持 connections 属性以限制中间件的范围,以及 priority 属性以更改已注册中间件的执行顺序。

注意

中间件是在 doctrine/dbal 的 3.2 版本中引入的,并且至少需要 doctrine/doctrine-bundle 的 2.6 版本才能像上面所示的那样在 Symfony 中集成它们。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本