diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index c7d83123..edf69316 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -1,5 +1,5 @@
parameters:
- level: 1
+ level: 3
paths:
- src
- tests
@@ -7,3 +7,14 @@ parameters:
excludePaths:
- src/Command/Proxy/ConvertMappingDoctrineCommand.php
- src/Command/Proxy/EnsureProductionSettingsDoctrineCommand.php
+ ignoreErrors:
+ # Available in ORM < 3 only
+ - '#Doctrine\\ORM\\Tools\\EntityGenerator.#'
+ - '#Doctrine\\ORM\\Tools\\DisconnectedClassMetadataFactory.#'
+ - '#Doctrine\\ORM\\Tools\\Export\\ClassMetadataExporter.#'
+ # phpstan has no array shape intersection support https://github.com/phpstan/phpstan/issues/12414
+ - message: '#unresolvable type.#'
+ path: src/DataCollector/DoctrineDataCollector.php
+ # Probably needs Symfony plugin
+ - message: '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\Node#'
+ path: src/DependencyInjection/Configuration.php
diff --git a/src/Command/DoctrineCommand.php b/src/Command/DoctrineCommand.php
index da787f7a..056e4eda 100644
--- a/src/Command/DoctrineCommand.php
+++ b/src/Command/DoctrineCommand.php
@@ -3,12 +3,14 @@
namespace Doctrine\Bundle\DoctrineBundle\Command;
use Doctrine\DBAL\Connection;
-use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\Persistence\ManagerRegistry;
use InvalidArgumentException;
use Symfony\Component\Console\Command\Command;
+use function assert;
+
/**
* Base class for Doctrine console commands to extend from.
*
@@ -29,12 +31,9 @@ public function __construct(ManagerRegistry $doctrine)
* get a doctrine entity generator
*
* @return EntityGenerator
- *
- * @psalm-suppress UndefinedDocblockClass ORM < 3 specific
*/
protected function getEntityGenerator()
{
- /** @phpstan-ignore class.notFound */
$entityGenerator = new EntityGenerator();
$entityGenerator->setGenerateAnnotations(false);
$entityGenerator->setGenerateStubMethods(true);
@@ -52,7 +51,7 @@ protected function getEntityGenerator()
* @param string $name
* @param int|null $shardId
*
- * @return EntityManager
+ * @return EntityManagerInterface
*/
protected function getEntityManager($name, $shardId = null)
{
@@ -62,6 +61,8 @@ protected function getEntityManager($name, $shardId = null)
throw new InvalidArgumentException('Shards are not supported anymore using doctrine/dbal >= 3');
}
+ assert($manager instanceof EntityManagerInterface);
+
return $manager;
}
diff --git a/src/Command/ImportMappingDoctrineCommand.php b/src/Command/ImportMappingDoctrineCommand.php
index 44ca4465..28a68d8a 100644
--- a/src/Command/ImportMappingDoctrineCommand.php
+++ b/src/Command/ImportMappingDoctrineCommand.php
@@ -2,6 +2,7 @@
namespace Doctrine\Bundle\DoctrineBundle\Command;
+use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\Driver\DatabaseDriver;
use Doctrine\ORM\Tools\Console\MetadataFilter;
use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
@@ -13,6 +14,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use function assert;
use function chmod;
use function dirname;
use function file_put_contents;
@@ -91,6 +93,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$namespaceOrBundle = $input->getArgument('name');
if (isset($this->bundles[$namespaceOrBundle])) {
+ /** @phpstan-ignore method.notFound */
$bundle = $this->getApplication()->getKernel()->getBundle($namespaceOrBundle);
$namespace = $bundle->getNamespace() . '\Entity';
@@ -121,13 +124,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$em = $this->getEntityManager($input->getOption('em'));
+ /* @phpstan-ignore method.notFound (Available in DBAL < 4) */
$databaseDriver = new DatabaseDriver($em->getConnection()->getSchemaManager());
$em->getConfiguration()->setMetadataDriverImpl($databaseDriver);
$emName = $input->getOption('em');
$emName = $emName ? $emName : 'default';
- /* @phpstan-ignore class.notFound */
$cmf = new DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);
$metadata = $cmf->getAllMetadata();
@@ -135,6 +138,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($metadata) {
$output->writeln(sprintf('Importing mapping information from "%s" entity manager', $emName));
foreach ($metadata as $class) {
+ assert($class instanceof ClassMetadata);
$className = $class->name;
$class->name = $namespace . '\\' . $className;
if ($type === 'annotation') {
diff --git a/src/ConnectionFactory.php b/src/ConnectionFactory.php
index d762963b..4e9e3bef 100644
--- a/src/ConnectionFactory.php
+++ b/src/ConnectionFactory.php
@@ -119,7 +119,7 @@ public function createConnection(array $params, ?Configuration $config = null, ?
$connection = DriverManager::getConnection(...array_merge([$params, $config], $eventManager ? [$eventManager] : []));
$params = $this->addDatabaseSuffix(array_merge($connection->getParams(), $overriddenOptions));
$driver = $connection->getDriver();
- /** @psalm-suppress InvalidScalarArgument Bogus error, StaticServerVersionProvider implements Doctrine\DBAL\ServerVersionProvider */
+ /** @phpstan-ignore arguments.count (DBAL < 4.x doesn't accept an argument) */
$platform = $driver->getDatabasePlatform(
...(class_exists(StaticServerVersionProvider::class)
? [new StaticServerVersionProvider($params['serverVersion'] ?? $params['primary']['serverVersion'] ?? '')]
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 06cf3dbd..0de8099a 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -277,6 +277,8 @@ private function getDbalConnectionsNode(): ArrayNodeDefinition
->prototype('array');
$this->configureDbalDriverNode($replicaNode);
+ assert($node instanceof ArrayNodeDefinition);
+
return $node;
}
@@ -822,6 +824,8 @@ private function getOrmEntityManagersNode(): ArrayNodeDefinition
->end()
->end();
+ assert($node instanceof ArrayNodeDefinition);
+
return $node;
}
@@ -850,6 +854,8 @@ private function getOrmCacheDriverNode(string $name): ArrayNodeDefinition
$node->addDefaultsIfNotSet();
}
+ assert($node instanceof ArrayNodeDefinition);
+
return $node;
}
diff --git a/src/Registry.php b/src/Registry.php
index 958956dc..f3275d5c 100644
--- a/src/Registry.php
+++ b/src/Registry.php
@@ -6,8 +6,8 @@
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\Proxy;
use ProxyManager\Proxy\LazyLoadingInterface;
-use Psr\Container\ContainerInterface;
use Symfony\Bridge\Doctrine\ManagerRegistry;
+use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\VarExporter\LazyObjectInterface;
use Symfony\Contracts\Service\ResetInterface;
@@ -23,7 +23,7 @@ class Registry extends ManagerRegistry implements ResetInterface
* @param string[] $connections
* @param string[] $entityManagers
*/
- public function __construct(ContainerInterface $container, array $connections, array $entityManagers, string $defaultConnection, string $defaultEntityManager)
+ public function __construct(Container $container, array $connections, array $entityManagers, string $defaultConnection, string $defaultEntityManager)
{
$this->container = $container;
@@ -51,7 +51,7 @@ public function getAliasNamespace($alias)
}
try {
- /** @psalm-suppress UndefinedMethod ORM < 3 specific */
+ /** @phpstan-ignore method.notFound (ORM < 3 specific) */
return $objectManager->getConfiguration()->getEntityNamespace($alias);
/* @phpstan-ignore class.notFound */
} catch (ORMException $e) {
diff --git a/src/Repository/ServiceEntityRepositoryProxy.php b/src/Repository/ServiceEntityRepositoryProxy.php
index 07dd6c0a..9755faca 100644
--- a/src/Repository/ServiceEntityRepositoryProxy.php
+++ b/src/Repository/ServiceEntityRepositoryProxy.php
@@ -27,6 +27,7 @@
*/
class ServiceEntityRepositoryProxy extends EntityRepository implements ServiceEntityRepositoryInterface
{
+ /** @var EntityRepository */
private ?EntityRepository $repository = null;
/** @param class-string $entityClass The class name of the entity this repository manages */
@@ -111,11 +112,13 @@ protected function getClassMetadata(): ClassMetadata
return ($this->repository ??= $this->resolveRepository())->getClassMetadata();
}
+ /** @phpstan-return AbstractLazyCollection&Selectable */
public function matching(Criteria $criteria): AbstractLazyCollection&Selectable
{
return ($this->repository ??= $this->resolveRepository())->matching($criteria);
}
+ /** @return EntityRepository */
private function resolveRepository(): EntityRepository
{
$manager = $this->registry->getManagerForClass($this->entityClass);
@@ -127,6 +130,9 @@ private function resolveRepository(): EntityRepository
));
}
- return new EntityRepository($manager, $manager->getClassMetadata($this->entityClass));
+ /** @var ClassMetadata $classMetadata */
+ $classMetadata = $manager->getClassMetadata($this->entityClass);
+
+ return new EntityRepository($manager, $classMetadata);
}
}
diff --git a/tests/DependencyInjection/Fixtures/Bundles/RepositoryServiceBundle/Repository/TestCustomClassRepoRepository.php b/tests/DependencyInjection/Fixtures/Bundles/RepositoryServiceBundle/Repository/TestCustomClassRepoRepository.php
index 9a67e056..0c33a76e 100644
--- a/tests/DependencyInjection/Fixtures/Bundles/RepositoryServiceBundle/Repository/TestCustomClassRepoRepository.php
+++ b/tests/DependencyInjection/Fixtures/Bundles/RepositoryServiceBundle/Repository/TestCustomClassRepoRepository.php
@@ -2,7 +2,7 @@
namespace Fixtures\Bundles\RepositoryServiceBundle\Repository;
-use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
/**
@@ -11,7 +11,7 @@
*/
class TestCustomClassRepoRepository extends EntityRepository
{
- public function getEntityManager(): EntityManager
+ public function getEntityManager(): EntityManagerInterface
{
return parent::getEntityManager();
}