From d82bf055424ce6da564619f54eb90890e5c78337 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 26 Jan 2025 17:28:19 +0100 Subject: [PATCH] bump to phpstan level 4 --- phpstan.neon.dist | 4 ++- .../DoctrineMetadataCacheWarmer.php | 3 +- src/Command/CreateDatabaseDoctrineCommand.php | 6 +++- src/Command/DropDatabaseDoctrineCommand.php | 6 +++- src/ConnectionFactory.php | 14 ++++++-- src/DataCollector/DoctrineDataCollector.php | 6 +--- .../Compiler/WellKnownSchemaFilterPass.php | 34 ------------------- src/DependencyInjection/DoctrineExtension.php | 5 --- src/DoctrineBundle.php | 2 -- src/Mapping/ClassMetadataFactory.php | 1 + src/Twig/DoctrineExtension.php | 3 +- .../AbstractDoctrineExtensionTest.php | 23 ++----------- .../Bundles/YamlBundle/Entity/Test.php | 1 + .../ServiceEntityRepositoryTest.php | 2 +- 14 files changed, 34 insertions(+), 76 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index edf693163..c8eb19f89 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 3 + level: 4 paths: - src - tests @@ -18,3 +18,5 @@ parameters: # Probably needs Symfony plugin - message: '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\Node#' path: src/DependencyInjection/Configuration.php + - '#Entity::\$id \(int\|null\) is never assigned int so it can be removed from the property type#' + - '#Entity::\$id is never read, only written#' diff --git a/src/CacheWarmer/DoctrineMetadataCacheWarmer.php b/src/CacheWarmer/DoctrineMetadataCacheWarmer.php index cb0654577..7bb9afe97 100644 --- a/src/CacheWarmer/DoctrineMetadataCacheWarmer.php +++ b/src/CacheWarmer/DoctrineMetadataCacheWarmer.php @@ -3,7 +3,6 @@ namespace Doctrine\Bundle\DoctrineBundle\CacheWarmer; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; use LogicException; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AbstractPhpFileCacheWarmer; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -36,7 +35,7 @@ protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, string } $metadataFactory = $this->entityManager->getMetadataFactory(); - if ($metadataFactory instanceof AbstractClassMetadataFactory && $metadataFactory->getLoadedMetadata()) { + if ($metadataFactory->getLoadedMetadata()) { throw new LogicException('DoctrineMetadataCacheWarmer must load metadata first, check priority of your warmers.'); } diff --git a/src/Command/CreateDatabaseDoctrineCommand.php b/src/Command/CreateDatabaseDoctrineCommand.php index 1d0b8948b..5e1bf2b40 100644 --- a/src/Command/CreateDatabaseDoctrineCommand.php +++ b/src/Command/CreateDatabaseDoctrineCommand.php @@ -67,7 +67,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int unset($params['dbname'], $params['path'], $params['url']); if ($connection->getDatabasePlatform() instanceof PostgreSQLPlatform) { - /** @psalm-suppress InvalidArrayOffset It's still available in DBAL 3.x that we need to support */ + /** + * for DBAL < 4 + * + * @phpstan-ignore nullCoalesce.offset + */ $params['dbname'] = $params['default_dbname'] ?? 'postgres'; } diff --git a/src/Command/DropDatabaseDoctrineCommand.php b/src/Command/DropDatabaseDoctrineCommand.php index 360e6daa7..e4d97680b 100644 --- a/src/Command/DropDatabaseDoctrineCommand.php +++ b/src/Command/DropDatabaseDoctrineCommand.php @@ -78,7 +78,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int unset($params['dbname'], $params['url']); if ($connection->getDatabasePlatform() instanceof PostgreSQLPlatform) { - /** @psalm-suppress InvalidArrayOffset It's still available in DBAL 3.x that we need to support */ + /** + * for DBAL < 4 + * + * @phpstan-ignore nullCoalesce.offset + */ $params['dbname'] = $params['default_dbname'] ?? 'postgres'; } diff --git a/src/ConnectionFactory.php b/src/ConnectionFactory.php index f2862f2a4..915d226df 100644 --- a/src/ConnectionFactory.php +++ b/src/ConnectionFactory.php @@ -44,6 +44,7 @@ class ConnectionFactory 'sqlite3' => 'pdo_sqlite', ]; + /** @phpstan-ignore property.onlyWritten */ private readonly DsnParser $dsnParser; private bool $initialized = false; @@ -76,7 +77,7 @@ public function createConnection(array $params, Configuration|null $config = nul } $overriddenOptions = []; - /** @psalm-suppress InvalidArrayOffset We should adjust when https://github.com/vimeo/psalm/issues/8984 is fixed */ + /** @phpstan-ignore isset.offset */ if (isset($params['connection_override_options'])) { trigger_deprecation('doctrine/doctrine-bundle', '2.4', 'The "connection_override_options" connection parameter is deprecated'); $overriddenOptions = $params['connection_override_options']; @@ -96,7 +97,7 @@ public function createConnection(array $params, Configuration|null $config = nul } } - /** @psalm-suppress InvalidArrayOffset We should adjust when https://github.com/vimeo/psalm/issues/8984 is fixed */ + /** @phpstan-ignore booleanOr.rightAlwaysFalse, isset.offset, isset.offset */ if (! isset($params['pdo']) && (! isset($params['charset']) || $overriddenOptions || isset($params['dbname_suffix']))) { $wrapperClass = null; @@ -251,14 +252,21 @@ private function addDatabaseSuffix(array $params): array * @phpstan-return Params * * @throws DBALException + * + * @phpstan-ignore throws.unusedType */ private function parseDatabaseUrl(array $params): array { - /** @psalm-suppress InvalidArrayOffset Need to be compatible with DBAL < 4, which still has `$params['url']` */ + /** + * for DBAL < 4 + * + * @phpstan-ignore isset.offset + */ if (! isset($params['url'])) { return $params; } + /** @phpstan-ignore deadCode.unreachable */ try { $parsedParams = $this->dsnParser->parse($params['url']); } catch (MalformedDsnException $e) { diff --git a/src/DataCollector/DoctrineDataCollector.php b/src/DataCollector/DoctrineDataCollector.php index c2e3b54fb..fe2674546 100644 --- a/src/DataCollector/DoctrineDataCollector.php +++ b/src/DataCollector/DoctrineDataCollector.php @@ -7,10 +7,8 @@ use Doctrine\ORM\Cache\Logging\CacheLoggerChain; use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Tools\SchemaValidator; use Doctrine\Persistence\ManagerRegistry; -use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector as BaseCollector; use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; use Symfony\Component\HttpFoundation\Request; @@ -54,6 +52,7 @@ class DoctrineDataCollector extends BaseCollector /** * @var mixed[][]|null * @phpstan-var ?array> + * @phpstan-ignore property.unusedType */ private array|null $groupedQueries = null; @@ -94,10 +93,7 @@ public function collect(Request $request, Response $response, Throwable|null $ex $factory = $em->getMetadataFactory(); $validator = new SchemaValidator($em); - assert($factory instanceof AbstractClassMetadataFactory); - foreach ($factory->getLoadedMetadata() as $class) { - assert($class instanceof ClassMetadata); if (isset($entities[$name][$class->getName()])) { continue; } diff --git a/src/DependencyInjection/Compiler/WellKnownSchemaFilterPass.php b/src/DependencyInjection/Compiler/WellKnownSchemaFilterPass.php index 7017b26c4..cafd86028 100644 --- a/src/DependencyInjection/Compiler/WellKnownSchemaFilterPass.php +++ b/src/DependencyInjection/Compiler/WellKnownSchemaFilterPass.php @@ -4,10 +4,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - -use function array_keys; -use function method_exists; /** * Blacklist tables used by well-known Symfony classes. @@ -21,35 +17,5 @@ class WellKnownSchemaFilterPass implements CompilerPassInterface /** @return void */ public function process(ContainerBuilder $container) { - $blacklist = []; - - foreach ($container->getDefinitions() as $definition) { - if ($definition->isAbstract() || $definition->isSynthetic()) { - continue; - } - - if ($definition->getClass() !== PdoSessionHandler::class) { - continue; - } - - $table = $definition->getArguments()[1]['db_table'] ?? 'sessions'; - - if (! method_exists($definition->getClass(), 'configureSchema')) { - $blacklist[] = $table; - } - - break; - } - - if (! $blacklist) { - return; - } - - $definition = $container->getDefinition('doctrine.dbal.well_known_schema_asset_filter'); - $definition->replaceArgument(0, $blacklist); - - foreach (array_keys($container->getParameter('doctrine.connections')) as $name) { - $definition->addTag('doctrine.dbal.schema_filter', ['connection' => $name]); - } } } diff --git a/src/DependencyInjection/DoctrineExtension.php b/src/DependencyInjection/DoctrineExtension.php index f5de6d2bd..6d2c95c79 100644 --- a/src/DependencyInjection/DoctrineExtension.php +++ b/src/DependencyInjection/DoctrineExtension.php @@ -18,7 +18,6 @@ use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface; use Doctrine\DBAL\Schema\LegacySchemaManagerFactory; -use Doctrine\ORM\Configuration as OrmConfiguration; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Events; use Doctrine\ORM\Id\AbstractIdGenerator; @@ -697,10 +696,6 @@ protected function loadOrmEntityManager(array $entityManager, ContainerBuilder $ $methods['setEagerFetchBatchSize'] = $entityManager['fetch_mode_subselect_batch_size']; } - if (! method_exists(OrmConfiguration::class, 'setLazyGhostObjectEnabled')) { - unset($methods['setLazyGhostObjectEnabled']); - } - $listenerId = sprintf('doctrine.orm.%s_listeners.attach_entity_listeners', $entityManager['name']); $listenerDef = $container->setDefinition($listenerId, new Definition('%doctrine.orm.listeners.attach_entity_listeners.class%')); $listenerTagParams = ['event' => 'loadClassMetadata']; diff --git a/src/DoctrineBundle.php b/src/DoctrineBundle.php index 1ea4bf623..3dd9df117 100644 --- a/src/DoctrineBundle.php +++ b/src/DoctrineBundle.php @@ -12,7 +12,6 @@ use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\RemoveLoggingMiddlewarePass; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\RemoveProfilerControllerPass; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass; -use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\WellKnownSchemaFilterPass; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Proxy\Autoloader; use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver; @@ -68,7 +67,6 @@ public function process(ContainerBuilder $container): void $container->addCompilerPass(new EntityListenerPass()); $container->addCompilerPass(new ServiceRepositoryCompilerPass()); $container->addCompilerPass(new IdGeneratorPass()); - $container->addCompilerPass(new WellKnownSchemaFilterPass()); $container->addCompilerPass(new DbalSchemaFilterPass()); $container->addCompilerPass(new CacheSchemaSubscriberPass(), PassConfig::TYPE_BEFORE_REMOVING, -10); $container->addCompilerPass(new RemoveProfilerControllerPass()); diff --git a/src/Mapping/ClassMetadataFactory.php b/src/Mapping/ClassMetadataFactory.php index a04a16ab5..2d250a0b7 100644 --- a/src/Mapping/ClassMetadataFactory.php +++ b/src/Mapping/ClassMetadataFactory.php @@ -23,6 +23,7 @@ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonS return; } + /** @phpstan-ignore function.impossibleType, instanceof.alwaysFalse */ assert($customGeneratorDefinition['instance'] instanceof AbstractIdGenerator); $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM); diff --git a/src/Twig/DoctrineExtension.php b/src/Twig/DoctrineExtension.php index f2e9a0017..7f5bf512f 100644 --- a/src/Twig/DoctrineExtension.php +++ b/src/Twig/DoctrineExtension.php @@ -115,6 +115,7 @@ public static function escapeFunction(mixed $parameter) */ public function replaceQueryParameters($query, $parameters) { + /** @phpstan-ignore instanceof.alwaysTrue */ if ($parameters instanceof Data) { $parameters = $parameters->getValue(true); } @@ -130,7 +131,7 @@ public function replaceQueryParameters($query, $parameters) static function ($matches) use ($parameters, &$i) { $key = substr($matches[0], 1); - if (! array_key_exists($i, $parameters) && ($key === false || ! array_key_exists($key, $parameters))) { + if (! array_key_exists($i, $parameters) && ! array_key_exists($key, $parameters)) { return $matches[0]; } diff --git a/tests/DependencyInjection/AbstractDoctrineExtensionTest.php b/tests/DependencyInjection/AbstractDoctrineExtensionTest.php index 5fd8dcad7..9fe2f9c04 100644 --- a/tests/DependencyInjection/AbstractDoctrineExtensionTest.php +++ b/tests/DependencyInjection/AbstractDoctrineExtensionTest.php @@ -39,7 +39,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; use Symfony\Component\Security\Core\User\UserInterface; use function array_filter; @@ -1197,20 +1196,8 @@ public function testWellKnownSchemaFilterDefaultTables(): void $this->assertInstanceOf(BlacklistSchemaAssetFilter::class, $filter); - if (method_exists(PdoSessionHandler::class, 'configureSchema')) { - $this->assertNotSame([['sessions']], $definition->getArguments()); - $this->assertTrue($filter->__invoke('sessions')); - } else { - $this->assertSame([['sessions']], $definition->getArguments()); - - $this->assertSame([['connection' => 'connection1'], ['connection' => 'connection2'], ['connection' => 'connection3']], $definition->getTag('doctrine.dbal.schema_filter')); - - $definition = $container->getDefinition('doctrine.dbal.connection1_schema_asset_filter_manager'); - - $this->assertEquals([new Reference('doctrine.dbal.well_known_schema_asset_filter'), new Reference('doctrine.dbal.connection1_regex_schema_filter')], $definition->getArgument(0)); - $this->assertFalse($filter->__invoke('sessions')); - } - + $this->assertNotSame([['sessions']], $definition->getArguments()); + $this->assertTrue($filter->__invoke('sessions')); $this->assertTrue($filter->__invoke('anything_else')); } @@ -1231,11 +1218,7 @@ public function testWellKnownSchemaFilterOverriddenTables(): void $this->assertInstanceOf(BlacklistSchemaAssetFilter::class, $filter); - if (method_exists(PdoSessionHandler::class, 'configureSchema')) { - $this->assertTrue($filter->__invoke('app_session')); - } else { - $this->assertFalse($filter->__invoke('app_session')); - } + $this->assertTrue($filter->__invoke('app_session')); } public function testEntityListenerResolver(): void diff --git a/tests/DependencyInjection/Fixtures/Bundles/YamlBundle/Entity/Test.php b/tests/DependencyInjection/Fixtures/Bundles/YamlBundle/Entity/Test.php index aebd396a6..ad3da4a8d 100644 --- a/tests/DependencyInjection/Fixtures/Bundles/YamlBundle/Entity/Test.php +++ b/tests/DependencyInjection/Fixtures/Bundles/YamlBundle/Entity/Test.php @@ -4,5 +4,6 @@ class Test { + /** @phpstan-ignore property.unused */ private mixed $id; } diff --git a/tests/Repository/ServiceEntityRepositoryTest.php b/tests/Repository/ServiceEntityRepositoryTest.php index bd4fdc3fc..7b87208f7 100644 --- a/tests/Repository/ServiceEntityRepositoryTest.php +++ b/tests/Repository/ServiceEntityRepositoryTest.php @@ -41,7 +41,7 @@ public function testConstructInitializesWhenImplementingLazyObjectInterface(): v $registry = $this->getMockBuilder(ManagerRegistry::class)->getMock(); $this->expectException(LogicException::class); - /* @phpstan-ignore class.notFound */ + /* @phpstan-ignore class.notFound, expr.resultUnused */ new class ($registry, TestEntity::class) extends ServiceEntityRepository implements LazyObjectInterface { use LazyGhostTrait; };