symfony 既然“setSQLLogger()”已被弃用,如何使用中间件记录Doctrine 3中的查询执行时间?

jk9hmnmh  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(127)

Doctrine已经弃用了它的->setSQLLogger(),转而支持中间件。
我找不到任何方法来记录查询的开始和结束以获得执行时间。
以前,它可以像在这个问题中关于Symfony2一样完成。
我应该创建什么样的中间件才能记录查询的执行时间?
现在,我只启用了日志记录,但这只是在执行查询之前记录查询。
我发现所有的查询都被收集在DebugDataHolder中,所以作为替代方案,它将在请求结束时记录所有查询:

use Doctrine\SqlFormatter\SqlFormatter;

class DatabaseFormatter implements FormatterInterface
{
    private string $id;
    private SqlFormatter $formatter;

    public function __construct(
        private DebugDataHolder $dataHolder,
    ) {
    }

    public function afterRequest() 
    {
        $queries = $this->dataHolder->getData();

        // ...
    }
}
wqnecbli

wqnecbli1#

我已经分析了Symfony是如何添加其中间件的,并编译了以下代码,可以对查询执行任何需要的操作:
首先按照this doc中的说明创建基本中间件

namespace App\Doctrine;

use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface;

class Middleware implements MiddlewareInterface
{
    public function __construct(
        /* ...dependencies from Symfony DI */
    ) {
    }

    public function wrap(DriverInterface $driver): Driver
    {
        // \App\Doctrine\Driver
        return new Driver($driver, /* ...dependencies */);
    }
}

然后添加额外的中间件:

namespace App\Doctrine;

use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;

final class Driver extends AbstractDriverMiddleware
{
    public function __construct(
        DriverInterface $driver,
        /* ...dependencies */
    ) {
        parent::__construct($driver);
    }

    public function connect(array $params): Connection
    {
        // \App\Doctrine\Connection
        return new Connection(parent::connect($params), /* ...dependencies */);
    }
}
namespace App\Doctrine;

use App\Log\Formatter\DatabaseFormatter;
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware;
use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\Driver\Statement as StatementInterface;

class Connection extends AbstractConnectionMiddleware
{
    public function __construct(
        ConnectionInterface $connection,
    ) {
        parent::__construct($connection);
    }

    public function prepare(string $sql): StatementInterface
    {
        // \App\Doctrine\Driver
        return new Statement(parent::prepare($sql), $sql);
    }

    /*
     * Overwrite any method from parent class with features
     */
}
namespace App\Doctrine;

use Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware;
use Doctrine\DBAL\Driver\Statement as StatementInterface;

final class Statement extends AbstractStatementMiddleware
{
    private array $params = [];
    private array $types = [];

    public function __construct(
        StatementInterface $statement,
        private string $sql,
    ) {
        parent::__construct($statement);
    }

    /*
     * Overwrite any method from parent class with features.
     */
}

Connection类在进行直接请求时使用,Statement在进行准备语句时使用。

相关问题