Repository: doctrine/persistence (language: php)

Issue:
Unexpected response returned from `AbstractManagerRegistry::getManagerNames()`
The `ManagerRegistry::getManagerNames()` should return `An array of object manager names. string[]`

https://github.com/doctrine/persistence/blob/0130920efd696cf5480744f499672b2d4ca47c85/lib/Doctrine/Persistence/ManagerRegistry.php#L65-L70

But the implementation in `AbstractManagerRegistry` returns an array of serviceId indexed by name.

https://github.com/doctrine/persistence/blob/0130920efd696cf5480744f499672b2d4ca47c85/lib/Doctrine/Persistence/AbstractManagerRegistry.php#L194-L197

I'm not sure what is the expected response. I would expect that `getManagerNames` returned `['foo', 'bar']`. I would expect such code worked: But this is not the case.

```php
foreach ($this->registry->getManagerNames() as $name) {
  dump($this->registry->getManager($name));
}
```

But fixing it in the `AbstractManagerRegistry` class could be a BC break.
Otherwise, we should improve the documentation of the interface.


Discussion / hints:

Fix patch:
diff --git a/composer.json b/composer.json
index f85a423d..9e4dc237 100644
--- a/composer.json
+++ b/composer.json
@@ -36,7 +36,7 @@
         "doctrine/common": "^3.0",
         "phpunit/phpunit": "^8.0 || ^9.0",
         "symfony/cache": "^4.4 || ^5.0 || ^6.0",
-        "vimeo/psalm": "4.13.1"
+        "vimeo/psalm": "4.20.0"
     },
     "conflict": {
         "doctrine/annotations": "<1.7 || >=2.0",
diff --git a/lib/Doctrine/Persistence/ManagerRegistry.php b/lib/Doctrine/Persistence/ManagerRegistry.php
index 831b08dd..34483de1 100644
--- a/lib/Doctrine/Persistence/ManagerRegistry.php
+++ b/lib/Doctrine/Persistence/ManagerRegistry.php
@@ -65,9 +65,12 @@ public function resetManager(?string $name = null);
     public function getAliasNamespace(string $alias);
 
     /**
-     * Gets all object manager names.
+     * Gets all object manager names and associated service IDs. A service ID
+     * is a string that allows to obtain an object manager, typically from a
+     * PSR-11 container.
      *
-     * @return array<string, string> An array of object manager names.
+     * @return array<string,string> An array with object manager names as keys,
+     *                              and service IDs as values.
      */
     public function getManagerNames();
 
diff --git a/psalm.xml b/psalm.xml
index 91803442..93b5eae9 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -17,24 +17,13 @@
         </ignoreFiles>
     </projectFiles>
     <issueHandlers>
-        <RedundantCondition>
+        <TypeDoesNotContainType>
             <errorLevel type="suppress">
-                <!-- see https://github.com/JetBrains/phpstorm-stubs/pull/877 -->
-                <file name="lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php"/>
-            </errorLevel>
-        </RedundantCondition>
-        <InvalidNullableReturnType>
-            <errorLevel type="suppress">
-                <!-- see https://github.com/vimeo/psalm/issues/5193 -->
-                <file name="lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php"/>
-            </errorLevel>
-        </InvalidNullableReturnType>
-        <NullableReturnStatement>
-            <errorLevel type="suppress">
-                <!-- see https://github.com/vimeo/psalm/issues/5193 -->
-                <file name="lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php"/>
+                <!-- Expected class list that is not a list<class-string> -->
+                <file name="tests/Doctrine/Tests/Persistence/Mapping/DefaultFileLocatorTest.php"/>
+                <file name="tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php"/>
             </errorLevel>
-        </NullableReturnStatement>
+        </TypeDoesNotContainType>
         <NullArgument>
             <errorLevel type="suppress">
                 <file name="tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php"/>


Test patch:
diff --git a/tests/Doctrine/Tests/Persistence/Mapping/AbstractClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/AbstractClassMetadataFactoryTest.php
new file mode 100644
index 00000000..8a4dec43
--- /dev/null
+++ b/tests/Doctrine/Tests/Persistence/Mapping/AbstractClassMetadataFactoryTest.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Tests\Persistence\Mapping;
+
+use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
+use Doctrine\Persistence\Mapping\ClassMetadata;
+use Doctrine\Persistence\Mapping\Driver\MappingDriver;
+use Doctrine\Tests\DoctrineTestCase;
+
+final class AbstractClassMetadataFactoryTest extends DoctrineTestCase
+{
+    public function testItSkipsTransientClasses(): void
+    {
+        $cmf = $this->getMockForAbstractClass(AbstractClassMetadataFactory::class);
+        $cmf
+            ->method('newClassMetadataInstance')
+            ->withConsecutive([SomeGrandParentEntity::class], [SomeEntity::class])
+            ->willReturnOnConsecutiveCalls(
+                $this->createMock(ClassMetadata::class),
+                $this->createMock(ClassMetadata::class)
+            );
+        $driver = $this->createMock(MappingDriver::class);
+        $cmf->method('getDriver')
+            ->willReturn($driver);
+
+        $driver->expects(self::exactly(2))
+            ->method('isTransient')
+            ->withConsecutive(
+                [SomeGrandParentEntity::class],
+                [SomeParentEntity::class]
+            )
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $cmf->getMetadataFor(SomeEntity::class);
+    }
+}
+
+class SomeGrandParentEntity
+{
+}
+
+class SomeParentEntity extends SomeGrandParentEntity
+{
+}
+
+final class SomeEntity extends SomeParentEntity
+{
+}