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

fix: handle repeatable attributes #8756

Merged
merged 7 commits into from
Jun 13, 2021
Merged

Conversation

ph-fritsche
Copy link
Contributor

@ph-fritsche ph-fritsche commented Jun 9, 2021

Introduces isTransient on AttributeDriver for better handling of repeatable attributes. Cleans up AttributeReader API a little.

Closes #8755

$classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className));

foreach ($classAnnotations as $a) {
$annot = is_array($a) ? $a[0] : $a;
Copy link
Member

Choose a reason for hiding this comment

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

@ph-fritsche can $a really be an array?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

            $annot = /* is_array($a) ? $a[0] : */ $a;

results in phpunit reporting:

There was 1 error:

1) Doctrine\Tests\ORM\Mapping\AttributeDriverTest::testIsTransientWithRepeatableAttributes
TypeError: get_class(): Argument #1 ($object) must be of type object, array given

/workspaces/misc/doctrine-orm/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php:52
/workspaces/misc/doctrine-orm/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php:85

due to:

public function getClassAnnotations(ReflectionClass $class): array
{
return $this->convertToAttributeInstances($class->getAttributes());

private function convertToAttributeInstances(array $attributes): array
{
$instances = [];
foreach ($attributes as $attribute) {
// Make sure we only get Doctrine Annotations
if (! is_subclass_of($attribute->getName(), Annotation::class)) {
continue;
}
$instance = $attribute->newInstance();
if ($this->isRepeatable($attribute->getName())) {
$instances[$attribute->getName()][] = $instance;
} else {
$instances[$attribute->getName()] = $instance;
}
}
return $instances;

Copy link
Member

Choose a reason for hiding this comment

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

Indeed. The phpdoc of convertToAttributeInstances is wrong, this is why the build fails.

Copy link
Member

Choose a reason for hiding this comment

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

Also, the phpdoc of Doctrine\Common\Annotations\Reader is wrong, and that's in another package 😬

Copy link
Member

Choose a reason for hiding this comment

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

Or rather AttributeReader does not implement the interface it says it implements. Widening the return type in the interface wouldn't be a BC break for classes implementing it, but it would be a BC break for calling code. Not sure what the best course of action would be here @beberlei . I think we should widen it in doctrine/annotations, but to be clean, that would require a major release 😬 or since it's just phpdoc, we pray it does not break to many static analysis builds and release it as a minor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe Doctrine\ORM\AttributeDriver should not extend Doctrine\Persistence\Mapping\Driver\AnnotationDriver at all.
How about we internally refactor Doctrine\Persistence\Mapping\Driver\AnnotationDriver::getAllClassNames into another class that could be reused by Doctrine\ORM\AttributeDriver?
This way doctrine/persistence and doctrine/annotation would not have any breaking changes.

If you want to be sentimental about the version increment on this package, one could argue that the declaration of Doctrine\ORM\AttributeDriver was broken from the beginning in 2.9 so breaking that inheritance here might be released as a fix.

Copy link
Member

Choose a reason for hiding this comment

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

That is a course of action we could take for the next minor release. To fix this bug the small solution plus suppression of tooling errors is my preference.

Copy link
Member

Choose a reason for hiding this comment

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

I just thought of another quite simple solution that does not imply changing other packages: let's use an iterable object instead of an array to represent a bug of attributes. As a bonus it will make the code clearer and will answer can $a really be an array? because you will have $a instanceof RepeatableAttributeCollection instead of is_array($a). WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Here is what it would look like: ph-fritsche#1

greg0ire and others added 4 commits June 11, 2021 09:05
A reader is supposed to only ever return objects. By introducing
RepeatableAttributeCollection, we fulfill the interface and improve
clarity.
@ph-fritsche ph-fritsche requested a review from greg0ire June 12, 2021 08:04
@beberlei
Copy link
Member

Can you exclude AttributeReader from php-stan and psalm analysis for now? We should upgrade to check with 8.0 in 2.10 branch.

@beberlei
Copy link
Member

@ph-fritsche just thought the ping pong fixing some config changes might going to be tedious and made the change myself for now. Lets see what the CI says about this.

beberlei
beberlei previously approved these changes Jun 12, 2021
Copy link
Member

@beberlei beberlei left a comment

Choose a reason for hiding this comment

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

This is good for now to fix the error.

I would say we could improve this in the future (2.10) by changing AttributeReader to have only three functions getAnnotations() : array<Annotation>, getFilteredAnnotations(string $className) : array<Annotation> and getAnnotation(string $className) : Annotation which throws when the class name is repeatable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

bug: AttributeDriver throws error for repeatable attributes
4 participants