-
-
Notifications
You must be signed in to change notification settings - Fork 912
Fix strict typing exception when the propertyName is a number #1055
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
Conversation
@@ -63,7 +63,7 @@ public function create(string $resourceClass, array $options = []): PropertyName | ||
// Properties | ||
foreach ($reflectionClass->getProperties() as $reflectionProperty) { | ||
if (null !== $this->reader->getPropertyAnnotation($reflectionProperty, ApiProperty::class)) { | ||
$propertyNames[$reflectionProperty->name] = true; | ||
$propertyNames[$reflectionProperty->name] = (string)$reflectionProperty->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we keep keys? $propertyNames[(string) $reflectionProperty->name]
should work no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I studied this a bit more, looks like the fix should be in PropertyNameCollection
:
--- a/src/Metadata/Property/PropertyNameCollection.php
+++ b/src/Metadata/Property/PropertyNameCollection.php
@@ -30,7 +30,9 @@ final class PropertyNameCollection implements \IteratorAggregate, \Countable
*/
public function __construct(array $properties = [])
{
- $this->properties = $properties;
+ $this->properties = array_map(function($property) {
+ return (string) $property;
+ }, $properties);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the key unfortunately php is converting the key to int, even when (string) is forced
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, still:
<?php
$t = [];
$t[118] = 'foo';
$t['bar'] = 'foo';
var_dump(array_map(function($v) {
return (string) $v;
}, array_keys($t)));
Outputs:
array(2) {
[0]=>
string(3) "118"
[1]=>
string(3) "bar"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup a centralized array_map is definitely better to handle this issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fond of the centralized array_map
solution. It looks hackish... This is not the reponsibility of PropertyNameCollection
to fix the data provided by friend classes. Other classes should provide data respecting the contract (an array of strings).
For the test, I'd recommend to create a new fixture class (avoid editing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your solution. It's elegant and faster than array_map
. I just left a minor comment regarding the useless cast. Thank you very much for fixing this!
@@ -63,7 +63,7 @@ public function create(string $resourceClass, array $options = []): PropertyName | ||
// Properties | ||
foreach ($reflectionClass->getProperties() as $reflectionProperty) { | ||
if (null !== $this->reader->getPropertyAnnotation($reflectionProperty, ApiProperty::class)) { | ||
$propertyNames[$reflectionProperty->name] = true; | ||
$propertyNames[$reflectionProperty->name] = (string)$reflectionProperty->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$reflectionProperty->name
is a always a string, so the cast isn't necessary (same everywhere).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we can make this even faster by using $propertyNames[] = $reflectionProperty->name;
if we rely on values :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really because we must ensure that properties are unique. If you use values, you'll need to call in_array
and it's an O(n) operation instead of O(1).
@@ -63,7 +63,7 @@ public function create(string $resourceClass, array $options = []): PropertyName | ||
// Properties | ||
foreach ($reflectionClass->getProperties() as $reflectionProperty) { | ||
if (null !== $this->reader->getPropertyAnnotation($reflectionProperty, ApiProperty::class)) { | ||
$propertyNames[$reflectionProperty->name] = true; | ||
$propertyNames[$reflectionProperty->name] = $reflectionProperty->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key may be useless now ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, it ensures the uniqueness.
I've just pushed the required tests |
@jocel1 may you change the target branch to |
rebase & squash done |
@@ -81,7 +81,7 @@ public function create(string $resourceClass, array $options = []): PropertyName | ||
} | ||
|
||
if (null !== $propertyName && null !== $this->reader->getMethodAnnotation($reflectionMethod, ApiProperty::class)) { | ||
$propertyNames[$propertyName] = true; | ||
$propertyNames[$propertyName] = (string) $propertyName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cast can be removed too.
@@ -41,7 +41,7 @@ public function create(string $resourceClass, array $options = []): PropertyName | ||
|
||
// Inherited from parent | ||
foreach ($this->decorated->create($resourceClass, $options) as $propertyName) { | ||
$propertyNames[$propertyName] = true; | ||
$propertyNames[$propertyName] = (string) $propertyName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cast can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mm no, this is this one in my case which was causing the issue : the symfony component PropertyInfoExtractor::getProperties() called through the PropertyInfoPropertyNameCollectionFactory returns an int instead of a string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the Symfony component suffers from the same bug. We may keep this fix temporarily but we should fix this behavior in Symfony as well then bump the minimal version required by API Platform.
Do you want to handle this? If you're out of time I can open the Symfony PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can handle this one, I'm definitely out of my time ;)
Travis and AppVeyor seem to have some troubles. Can you rebase and push force again? |
Thank you very much @jocel1! |
…(dunglas) This PR was merged into the 2.8 branch. Discussion ---------- [PropertyInfo] Prevent returning int values in some cases | Q | A | ------------- | --- | Branch? | 2.8 | Bug fix? | yes | New feature? | no <!-- don't forget updating src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | no <!-- don't forget updating UPGRADE-*.md files --> | Tests pass? | yes | Fixed tickets | api-platform/api-platform#282, api-platform/core#1055 | License | MIT | Doc PR | n/a PHP automatically converts array keys to an int if and only if it looks like an int... When a getter looks like `get123`, the ReflectionExtractor returns an array containing an int instead of a string. This PR fixes this. Commits ------- b190ec2 [PropertyInfo] Prevent returning int values in some cases.
Uh oh!
There was an error while loading. Please reload this page.