Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise Psalm level to 3 and add generics to ClassMetadata #159

Closed
wants to merge 13 commits into from

Conversation

franmomu
Copy link
Contributor

The first commits of this PR are changes in order to raise psalm level to 3. I've used 2.2.x as base thinking about adding the ClassMetadata generics as feature, but maybe I should split the PR in two targeting 2.1.x with the raising psalm level part.

@greg0ire
Copy link
Member

I don't have a strong opinion about the target branch. Do what you feel is best.

@franmomu franmomu force-pushed the metadata_generics branch from 3a240d7 to a3fc681 Compare April 2, 2021 16:58
@greg0ire
Copy link
Member

greg0ire commented Apr 3, 2021

Please run phpcbf

@franmomu franmomu force-pushed the metadata_generics branch from 1da1086 to 0489cb2 Compare April 3, 2021 19:12
@franmomu
Copy link
Contributor Author

franmomu commented Apr 3, 2021

Please run phpcbf

oops, didn't see that, done.

@greg0ire
Copy link
Member

greg0ire commented Apr 3, 2021

@orklah please review

@franmomu franmomu force-pushed the metadata_generics branch from 0489cb2 to d892fda Compare April 5, 2021 13:20
Copy link

@orklah orklah left a comment

Choose a reason for hiding this comment

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

Great job :)

@@ -218,6 +221,7 @@ public function getMetadataFor($className)

$realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
} else {
/** @psalm-var class-string $className */
Copy link

Choose a reason for hiding this comment

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

This should be specified in parameters instead of overrided with @var

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for reviewing! I remember struggling with this one:

// Check for namespace alias
if (strpos($className, ':') !== false) {
    [$namespaceAlias, $simpleClassName] = explode(':', $className, 2);

    $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
} else {
    /** @psalm-var class-string $className */
    $realClassName = $this->getRealClass($className);
}

$className can be a class-string or a class name string alias (App:Entity), I tried to move it to parameters as class-string|string but then psalm doesn't know that which one is receiving.

Copy link

Choose a reason for hiding this comment

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

nevermind then, I thought $className would always be a className. How naive :D

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe rename $className to $classNameOrClassNameAlias?
This will ease reading the code then

@@ -483,6 +491,8 @@ private function getRealClass(string $class): string
$this->createDefaultProxyClassNameResolver();
}

assert($this->proxyClassNameResolver instanceof ProxyClassNameResolver);
Copy link

Choose a reason for hiding this comment

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

asserting the variable is !== null would be semantically more meaningful I think

@@ -66,7 +66,7 @@ abstract class AnnotationDriver implements MappingDriver
/**
* Name of the entity annotations as keys.
*
* @var string[]
* @var array<class-string, mixed>
Copy link

Choose a reason for hiding this comment

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

was string[] plain wrong? If not, it should become array<class-string, string>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like it was wrong, I used mixed because looking at its use:

And here in tests we're using bool, I'll change it to array<class-string, int|bool>.

@@ -21,6 +21,9 @@ interface ReflectionService
* @return string[]
*
* @throws MappingException
*
* @psalm-param class-string $class
* @psalm-return class-string[]
Copy link

Choose a reason for hiding this comment

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

maybe use the extensive syntax if offset type is known?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only implementation I've seen (apart from the ones returning empty array) is

public function getParentClasses($class)
{
if (! class_exists($class)) {
throw MappingException::nonExistingClass($class);
}
return class_parents($class);
}

So I don't know if that can be improved.

@@ -39,5 +39,21 @@
<file name="tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php"/>
</errorLevel>
</NullArgument>
<PossiblyNullReference>
Copy link

Choose a reason for hiding this comment

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

Maybe leave a comment to explain why those couldn't be fixed and had to be ignored? It will be helpful for future contributions

@@ -24,7 +24,7 @@ public function testGetAllClassNames(): void

class SimpleAnnotationDriver extends AnnotationDriver
{
/** @var bool[] */
/** @var array<class-string, mixed> */
Copy link

Choose a reason for hiding this comment

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

should probably be array<class-string, bool>

$companyDriver = $this->createMock(MappingDriver::class);
$defaultDriver = $this->createMock(MappingDriver::class);
/** @psalm-var class-string */
$entityClassName = 'Doctrine\Tests\ORM\Mapping\DriverChainEntity';
Copy link

Choose a reason for hiding this comment

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

I think ::class should be used too (and eventually suppressed because the dependancy is not there) instead of being overrided

@@ -91,6 +92,8 @@ protected function onNotFoundMetadata($className)

/**
* {@inheritDoc}
*
* @param string $class
Copy link

Choose a reason for hiding this comment

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

I think I remember @inheritdoc have weird behaviour when a part is overrided. Maybe ditch it completely?

@@ -22,7 +22,7 @@ public function __construct(ObjectManager $wrapped)

class ObjectManagerDecoratorTest extends TestCase
{
/** @var MockObject|ObjectManager */
/** @var MockObject&ObjectManager */
Copy link

Choose a reason for hiding this comment

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

Not sure how IDE will react to that. Maybe in an @psalm-var?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting, I've been using it for a while because PHPStorm understands it, don't know others.

Copy link

Choose a reason for hiding this comment

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

IIRC, PHPStorm basically treat that the same way as "|" now. There was an issue on their bug tracker where they talked about that and they were not sure of what to do with that

}

/** @psalm-var class-string */
return $className;
Copy link

Choose a reason for hiding this comment

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

Maybe an assertion for class_exists could be used in the future instead of overriding? In a future version to avoid BC breaks maybe?

@franmomu franmomu force-pushed the metadata_generics branch 3 times, most recently from 9e8232b to 6b1745b Compare April 6, 2021 07:13
@franmomu franmomu force-pushed the metadata_generics branch from 6b1745b to df82d13 Compare April 6, 2021 07:26
@@ -118,7 +118,7 @@ public function testDefaultDriver(): void
self::assertNull($chain->getDefaultDriver());

$chain->setDefaultDriver($defaultDriver);
$chain->addDriver($companyDriver, 'Doctrine\Tests\Models\Company');
$chain->addDriver($companyDriver, 'Doctrine\Tests\Persistence\Mapping\Fixtures\Manager');
Copy link

Choose a reason for hiding this comment

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

This should be a ::class instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, this argument is a namespace.

@@ -41,17 +41,21 @@
</NullArgument>
<PossiblyNullReference>
<errorLevel type="suppress">
<!-- ReflectionProperty::getType() can return null, but there is ReflectionProperty::hasType()
Copy link

Choose a reason for hiding this comment

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

This has been fixed in Psalm recently:
vimeo/psalm#5258
Maybe Psalm can be upgraded?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is ReflectionProperty (instead of ReflectionParameter) I've created vimeo/psalm#5584 based on vimeo/psalm#5258, but after reading it again, IIUC, it won't work because ReflectionProperty is not immutable.

Copy link

Choose a reason for hiding this comment

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

Oh, my mistake then :)

@greg0ire
Copy link
Member

This can be closed, right?

@greg0ire greg0ire closed this Apr 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants