Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@
"require-dev": {
"doctrine/coding-standard": "^14",
"doctrine/orm": "^3.4.4",
"phpstan/phpstan": "2.1.1",
"phpstan/phpstan": "^2.1.13",
"phpstan/phpstan-phpunit": "2.0.3",
"phpstan/phpstan-strict-rules": "^2",
"phpstan/phpstan-symfony": "^2.0",
"phpstan/phpstan-symfony": "^2.0.9",
"phpunit/phpunit": "^12.3.10",
"psr/log": "^3.0",
"symfony/doctrine-messenger": "^6.4 || ^7.0 || ^8.0",
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
includes:
- vendor/phpstan/phpstan-symfony/extension.neon
parameters:
level: 7
level: 8
reportUnmatchedIgnoredErrors: true
paths:
- config
Expand Down
6 changes: 5 additions & 1 deletion src/Controller/ProfilerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ public function explainAction(string $token, string $connectionName, int $query)
{
$this->profiler->disable();

$profile = $this->profiler->loadProfile($token);
$profile = $this->profiler->loadProfile($token);
if ($profile === null) {
return new Response('Profile not found.', 404);
}

$collector = $profile->getCollector('db');

assert($collector instanceof DoctrineDataCollector);
Expand Down
15 changes: 9 additions & 6 deletions src/DataCollector/DoctrineDataCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
* types: ?array<array-key, Type|int|string|null>,
* count: int,
* index: int,
* executionPercent?: float
* executionPercent: float
* }
* @phpstan-type GroupedQueriesType = array<string, array<int, GroupedQueryItemType>>
* @phpstan-property DataType $data
Expand All @@ -77,6 +77,10 @@ public function __construct(
private readonly bool $shouldValidateSchema = true,
DebugDataHolder|null $debugDataHolder = null,
) {
if ($debugDataHolder === null) {
$debugDataHolder = new DebugDataHolder();
}

parent::__construct($registry, $debugDataHolder);
}

Expand Down Expand Up @@ -304,14 +308,13 @@ public function getGroupedQueries(): array

return $a['executionMS'] < $b['executionMS'] ? 1 : -1;
});
$this->groupedQueries[$connection] = $connectionGroupedQueries;
}

foreach ($this->groupedQueries as $connection => $queries) {
foreach ($queries as $i => $query) {
$this->groupedQueries[$connection][$i]['executionPercent'] =
foreach ($connectionGroupedQueries as $i => $query) {
$connectionGroupedQueries[$i]['executionPercent'] =
$this->executionTimePercentage($query['executionMS'], $totalExecutionMS);
}

$this->groupedQueries[$connection] = $connectionGroupedQueries;
Comment on lines -307 to +317
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are your sure about this change ? Because $totalExecutionMS need the first foreach to be well calculated

}

return $this->groupedQueries;
Expand Down
3 changes: 2 additions & 1 deletion src/DependencyInjection/Compiler/MiddlewaresPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public function process(ContainerBuilder $container): void
);
$middlewareRefs[$id] = [new Reference($childId), ++$i];

if (! is_subclass_of($abstractDef->getClass(), ConnectionNameAwareInterface::class)) {
$class = $abstractDef->getClass();
if ($class === null || ! is_subclass_of($class, ConnectionNameAwareInterface::class)) {
continue;
}

Expand Down
8 changes: 0 additions & 8 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ private function addDbalSection(ArrayNodeDefinition $node): void
// Key that should not be rewritten to the connection config
$excludedKeys = ['default_connection' => true, 'driver_schemes' => true, 'driver_scheme' => true, 'types' => true, 'type' => true];

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->children()
->arrayNode('dbal')
Expand Down Expand Up @@ -167,7 +166,6 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition

$this->configureDbalDriverNode($connectionNode);

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$connectionNode
->fixXmlConfig('option')
->fixXmlConfig('mapping_type')
Expand Down Expand Up @@ -214,7 +212,6 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition
->scalarNode('result_cache')->end()
->end();

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$replicaNode = $connectionNode
->children()
->arrayNode('replicas')
Expand All @@ -232,7 +229,6 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition
*/
private function configureDbalDriverNode(ArrayNodeDefinition $node): void
{
/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->validate()
->always(static function (array $values) {
Expand Down Expand Up @@ -370,7 +366,6 @@ private function addOrmSection(ArrayNodeDefinition $node): void
'controller_resolver' => true,
];

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->children()
->arrayNode('orm')
Expand Down Expand Up @@ -518,7 +513,6 @@ private function getOrmEntityListenersNode(): NodeDefinition
return ['entities' => $entities];
};

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->beforeNormalization()
// Yaml normalization
Expand Down Expand Up @@ -564,7 +558,6 @@ private function getOrmEntityManagersNode(): ArrayNodeDefinition
$treeBuilder = new TreeBuilder('entity_managers');
$node = $treeBuilder->getRootNode();

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
Expand Down Expand Up @@ -739,7 +732,6 @@ private function getOrmCacheDriverNode(string $name): ArrayNodeDefinition
$treeBuilder = new TreeBuilder($name);
$node = $treeBuilder->getRootNode();

/** @phpstan-ignore class.notFound (Phpstan Symfony extension does not know yet how to deal with these) */
$node
->beforeNormalization()
->ifString()
Expand Down
8 changes: 5 additions & 3 deletions src/DependencyInjection/DoctrineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,11 @@ private function loadMappingInformation(array $objectManager, ContainerBuilder $
throw new InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled.', $mappingName));
}

$mappingConfig = $this->getMappingDriverBundleConfigDefaults($mappingConfig, $bundle, $container, $bundleMetadata['path']);
if (! $mappingConfig) {
continue;
if ($bundleMetadata !== null) {
$mappingConfig = $this->getMappingDriverBundleConfigDefaults($mappingConfig, $bundle, $container, $bundleMetadata['path']);
if (! $mappingConfig) {
continue;
}
}
} elseif (! $mappingConfig['type']) {
$mappingConfig['type'] = 'attribute';
Expand Down
4 changes: 4 additions & 0 deletions src/DoctrineBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ public function process(ContainerBuilder $container): void

public function shutdown(): void
{
if ($this->container === null) {
return;
}

// Clear all entity managers to clear references to entities for GC
if ($this->container->hasParameter('doctrine.entity_managers')) {
foreach ($this->container->getParameter('doctrine.entity_managers') as $id) {
Expand Down
18 changes: 17 additions & 1 deletion src/Twig/DoctrineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\SqlFormatter\HtmlHighlighter;
use Doctrine\SqlFormatter\NullHighlighter;
use Doctrine\SqlFormatter\SqlFormatter;
use RuntimeException;
use Stringable;
use Symfony\Component\VarDumper\Cloner\Data;
use Twig\Extension\AbstractExtension;
Expand All @@ -24,11 +25,15 @@
use function is_array;
use function is_bool;
use function is_string;
use function preg_last_error;
use function preg_match;
use function preg_replace_callback;
use function sprintf;
use function strtoupper;
use function substr;

use const PREG_NO_ERROR;

/**
* This class contains the needed functions in order to do the query highlighting
*
Expand Down Expand Up @@ -116,7 +121,7 @@ public function replaceQueryParameters(string $query, array|Data $parameters): s

$i = 0;

return preg_replace_callback(
$result = preg_replace_callback(
'/(?<!\?)\?(?!\?)|(?<!:)(:[a-z0-9_]+)/i',
static function (array $matches) use ($parameters, &$i): string {
$key = substr($matches[0], 1);
Expand All @@ -133,6 +138,17 @@ static function (array $matches) use ($parameters, &$i): string {
},
$query,
);

$pregError = preg_last_error();
if ($pregError !== PREG_NO_ERROR) {
throw new RuntimeException(sprintf('Failed to replace query parameters: PCRE error %d', $pregError));
}

if ($result === null) {
throw new RuntimeException('Failed to replace query parameters: unexpected null result');
}

return $result;
}

public function prettifySql(string $sql): string
Expand Down
2 changes: 1 addition & 1 deletion tests/Command/DropDatabaseDoctrineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public static function provideIncompatibleDriverOptions(): Generator
}

/**
* @param list<mixed> $params Connection parameters
* @param array{url?: string, path?: string, driver: string} $params Connection parameters
* @psalm-param Params $params
*
* @return Stub&Container
Expand Down
8 changes: 5 additions & 3 deletions tests/DataCollector/DoctrineDataCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ public function testGetGroupedQueries(): void
*/
private function createEntityMetadata(string $entityFQCN): ClassMetadata
{
$metadata = new ClassMetadata($entityFQCN);
$metadata->name = $entityFQCN;
$metadata->reflClass = new ReflectionClass('stdClass');
$metadata = new ClassMetadata($entityFQCN);
$metadata->name = $entityFQCN;
/** @var ReflectionClass<object> $stdClassReflection */
$stdClassReflection = new ReflectionClass('stdClass');
$metadata->reflClass = $stdClassReflection;

return $metadata;
}
Expand Down
36 changes: 21 additions & 15 deletions tests/DependencyInjection/XMLSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,34 @@ public function testValidateSchema(string $file): void

$dbalElements = $dom->getElementsByTagNameNS($xmlns, 'dbal');
if ($dbalElements->length) {
$dbalDom = new DOMDocument('1.0', 'UTF-8');
$dbalNode = $dbalDom->importNode($dbalElements->item(0));
$configNode = $dbalDom->createElementNS($xmlns, 'config');
$configNode->appendChild($dbalNode);
$dbalDom->appendChild($configNode);
$dbalDom = new DOMDocument('1.0', 'UTF-8');
$dbalElement = $dbalElements->item(0);
if ($dbalElement !== null) {
$dbalNode = $dbalDom->importNode($dbalElement);
$configNode = $dbalDom->createElementNS($xmlns, 'config');
$configNode->appendChild($dbalNode);
$dbalDom->appendChild($configNode);

$ret = $dbalDom->schemaValidate(__DIR__ . '/../../config/schema/doctrine-1.0.xsd');
$this->assertTrue($ret, 'DoctrineBundle Dependency Injection XMLSchema did not validate this XML instance.');
$found = true;
$ret = $dbalDom->schemaValidate(__DIR__ . '/../../config/schema/doctrine-1.0.xsd');
$this->assertTrue($ret, 'DoctrineBundle Dependency Injection XMLSchema did not validate this XML instance.');
$found = true;
}
}

$ormElements = $dom->getElementsByTagNameNS($xmlns, 'orm');
if ($ormElements->length) {
$ormDom = new DOMDocument('1.0', 'UTF-8');
$ormNode = $ormDom->importNode($ormElements->item(0));
$configNode = $ormDom->createElementNS($xmlns, 'config');
$configNode->appendChild($ormNode);
$ormDom->appendChild($configNode);
$ormElement = $ormElements->item(0);
if ($ormElement !== null) {
$ormNode = $ormDom->importNode($ormElement);
$configNode = $ormDom->createElementNS($xmlns, 'config');
$configNode->appendChild($ormNode);
$ormDom->appendChild($configNode);

$ret = $ormDom->schemaValidate(__DIR__ . '/../../config/schema/doctrine-1.0.xsd');
$this->assertTrue($ret, 'DoctrineBundle Dependency Injection XMLSchema did not validate this XML instance.');
$found = true;
$ret = $ormDom->schemaValidate(__DIR__ . '/../../config/schema/doctrine-1.0.xsd');
$this->assertTrue($ret, 'DoctrineBundle Dependency Injection XMLSchema did not validate this XML instance.');
$found = true;
}
}

$this->assertTrue($found, 'Neither <doctrine:orm> nor <doctrine:dbal> elements found in given XML. Are namespaces configured correctly?');
Expand Down