Skip to content

Commit 122ec76

Browse files
committed
Allow to use a middleware instead of DbalLogger
1 parent 4834d9e commit 122ec76

File tree

12 files changed

+807
-42
lines changed

12 files changed

+807
-42
lines changed

phpunit.xml.dist

+8-7
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@
7373
<element key="time-sensitive">
7474
<array>
7575
<element key="0"><string>Cache\IntegrationTests</string></element>
76-
<element key="1"><string>Symfony\Component\Cache</string></element>
77-
<element key="2"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
78-
<element key="3"><string>Symfony\Component\Cache\Tests\Traits</string></element>
79-
<element key="4"><string>Symfony\Component\Cache\Traits</string></element>
80-
<element key="5"><string>Symfony\Component\Console</string></element>
81-
<element key="6"><string>Symfony\Component\HttpFoundation</string></element>
82-
<element key="7"><string>Symfony\Component\Uid</string></element>
76+
<element key="1"><string>Symfony\Bridge\Doctrine\Middleware\Debug</string></element>
77+
<element key="2"><string>Symfony\Component\Cache</string></element>
78+
<element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
79+
<element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element>
80+
<element key="5"><string>Symfony\Component\Cache\Traits</string></element>
81+
<element key="6"><string>Symfony\Component\Console</string></element>
82+
<element key="7"><string>Symfony\Component\HttpFoundation</string></element>
83+
<element key="8"><string>Symfony\Component\Uid</string></element>
8384
</array>
8485
</element>
8586
</array>

src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php

+30-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\DBAL\Types\ConversionException;
1616
use Doctrine\DBAL\Types\Type;
1717
use Doctrine\Persistence\ManagerRegistry;
18+
use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder;
1819
use Symfony\Component\HttpFoundation\Request;
1920
use Symfony\Component\HttpFoundation\Response;
2021
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
@@ -28,7 +29,6 @@
2829
*/
2930
class DoctrineDataCollector extends DataCollector
3031
{
31-
private ManagerRegistry $registry;
3232
private array $connections;
3333
private array $managers;
3434

@@ -37,9 +37,10 @@ class DoctrineDataCollector extends DataCollector
3737
*/
3838
private array $loggers = [];
3939

40-
public function __construct(ManagerRegistry $registry)
41-
{
42-
$this->registry = $registry;
40+
public function __construct(
41+
private ManagerRegistry $registry,
42+
private ?DebugDataHolder $debugDataHolder = null,
43+
) {
4344
$this->connections = $registry->getConnectionNames();
4445
$this->managers = $registry->getManagerNames();
4546
}
@@ -56,23 +57,43 @@ public function addLogger(string $name, DebugStack $logger)
5657
* {@inheritdoc}
5758
*/
5859
public function collect(Request $request, Response $response, \Throwable $exception = null)
60+
{
61+
$this->data = [
62+
'queries' => $this->collectQueries(),
63+
'connections' => $this->connections,
64+
'managers' => $this->managers,
65+
];
66+
}
67+
68+
private function collectQueries(): array
5969
{
6070
$queries = [];
71+
72+
if (null !== $this->debugDataHolder) {
73+
foreach ($this->debugDataHolder->getData() as $name => $data) {
74+
$queries[$name] = $this->sanitizeQueries($name, $data);
75+
}
76+
77+
return $queries;
78+
}
79+
6180
foreach ($this->loggers as $name => $logger) {
6281
$queries[$name] = $this->sanitizeQueries($name, $logger->queries);
6382
}
6483

65-
$this->data = [
66-
'queries' => $queries,
67-
'connections' => $this->connections,
68-
'managers' => $this->managers,
69-
];
84+
return $queries;
7085
}
7186

7287
public function reset()
7388
{
7489
$this->data = [];
7590

91+
if (null !== $this->debugDataHolder) {
92+
$this->debugDataHolder->reset();
93+
94+
return;
95+
}
96+
7697
foreach ($this->loggers as $logger) {
7798
$logger->queries = [];
7899
$logger->currentQuery = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\Debug;
13+
14+
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
15+
use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware;
16+
use Doctrine\DBAL\Driver\Result;
17+
use Doctrine\DBAL\Driver\Statement as DriverStatement;
18+
use Symfony\Component\Stopwatch\Stopwatch;
19+
20+
/**
21+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
22+
*/
23+
class Connection extends AbstractConnectionMiddleware
24+
{
25+
private int $nestingLevel = 0;
26+
27+
public function __construct(
28+
ConnectionInterface $connection,
29+
private DebugDataHolder $debugDataHolder,
30+
private ?Stopwatch $stopwatch,
31+
private string $connectionName,
32+
) {
33+
parent::__construct($connection);
34+
}
35+
36+
public function prepare(string $sql): DriverStatement
37+
{
38+
return new Statement(
39+
parent::prepare($sql),
40+
$this->debugDataHolder,
41+
$this->connectionName,
42+
$sql,
43+
);
44+
}
45+
46+
public function query(string $sql): Result
47+
{
48+
$this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql));
49+
50+
$this->stopwatch?->start('doctrine', 'doctrine');
51+
$query->start();
52+
$result = parent::query($sql);
53+
$query->stop();
54+
$this->stopwatch?->stop('doctrine');
55+
56+
return $result;
57+
}
58+
59+
public function exec(string $sql): int
60+
{
61+
$this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql));
62+
63+
$this->stopwatch?->start('doctrine', 'doctrine');
64+
$query->start();
65+
$affectedRows = parent::exec($sql);
66+
$query->stop();
67+
$this->stopwatch?->stop('doctrine');
68+
69+
return $affectedRows;
70+
}
71+
72+
public function beginTransaction(): bool
73+
{
74+
$query = null;
75+
if (1 === ++$this->nestingLevel) {
76+
$this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"'));
77+
}
78+
79+
$this->stopwatch?->start('doctrine', 'doctrine');
80+
$query?->start();
81+
$ret = parent::beginTransaction();
82+
$query?->stop();
83+
$this->stopwatch?->stop('doctrine');
84+
85+
return $ret;
86+
}
87+
88+
public function commit(): bool
89+
{
90+
$query = null;
91+
if (1 === $this->nestingLevel--) {
92+
$this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"'));
93+
}
94+
95+
$this->stopwatch?->start('doctrine', 'doctrine');
96+
$query?->start();
97+
$ret = parent::commit();
98+
$query?->stop();
99+
$this->stopwatch?->stop('doctrine');
100+
101+
return $ret;
102+
}
103+
104+
public function rollBack(): bool
105+
{
106+
$query = null;
107+
if (1 === $this->nestingLevel--) {
108+
$this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"'));
109+
}
110+
111+
$this->stopwatch?->start('doctrine', 'doctrine');
112+
$query?->start();
113+
$ret = parent::rollBack();
114+
$query?->stop();
115+
$this->stopwatch?->stop('doctrine');
116+
117+
return $ret;
118+
}
119+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\Debug;
13+
14+
/**
15+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
16+
*/
17+
class DebugDataHolder
18+
{
19+
private array $data = [];
20+
21+
public function addQuery(string $connectionName, Query $query): void
22+
{
23+
$this->data[$connectionName][] = [
24+
'sql' => $query->getSql(),
25+
'params' => $query->getParams(),
26+
'types' => $query->getTypes(),
27+
'executionMS' => static fn () => $query->getDuration(), // stop() may not be called at this point
28+
];
29+
}
30+
31+
public function getData(): array
32+
{
33+
foreach ($this->data as $connectionName => $dataForConn) {
34+
foreach ($this->data[$connectionName] as $idx => $data) {
35+
if (\is_callable($data['executionMS'])) {
36+
$this->data[$connectionName][$idx]['executionMS'] = $data['executionMS']();
37+
}
38+
}
39+
}
40+
41+
return $this->data;
42+
}
43+
44+
public function reset(): void
45+
{
46+
$this->data = [];
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\Debug;
13+
14+
use Doctrine\DBAL\Driver as DriverInterface;
15+
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
16+
use Symfony\Component\Stopwatch\Stopwatch;
17+
18+
/**
19+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
20+
*/
21+
class Driver extends AbstractDriverMiddleware
22+
{
23+
public function __construct(
24+
DriverInterface $driver,
25+
private DebugDataHolder $debugDataHolder,
26+
private ?Stopwatch $stopwatch,
27+
private string $connectionName,
28+
) {
29+
parent::__construct($driver);
30+
}
31+
32+
public function connect(array $params): Connection
33+
{
34+
return new Connection(
35+
parent::connect($params),
36+
$this->debugDataHolder,
37+
$this->stopwatch,
38+
$this->connectionName,
39+
);
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Middleware\Debug;
13+
14+
use Doctrine\DBAL\Driver as DriverInterface;
15+
use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface;
16+
use Symfony\Component\Stopwatch\Stopwatch;
17+
18+
/**
19+
* Middleware to collect debug data.
20+
*
21+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
22+
*/
23+
class Middleware implements MiddlewareInterface
24+
{
25+
public function __construct(
26+
private DebugDataHolder $debugDataHolder,
27+
private ?Stopwatch $stopwatch,
28+
private string $connectionName = 'default',
29+
) {
30+
}
31+
32+
public function wrap(DriverInterface $driver): DriverInterface
33+
{
34+
return new Driver($driver, $this->debugDataHolder, $this->stopwatch, $this->connectionName);
35+
}
36+
}

0 commit comments

Comments
 (0)