-
-
Notifications
You must be signed in to change notification settings - Fork 470
Test for PHP property access #2688
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
Changes from all commits
139e329
b471974
017de75
16cbaa1
b7aab4a
5bf8a53
9829c24
be73761
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,215 @@ | ||
| <?php declare(strict_types=1); | ||
|
|
||
| namespace Tests\Integration\Models; | ||
|
|
||
| use Tests\DBTestCase; | ||
| use Tests\Utils\Models\User; | ||
|
|
||
| final class PropertyAccessTest extends DBTestCase | ||
| { | ||
| public function testLaravelDatabaseProperty(): void | ||
| { | ||
| $name = 'foobar'; | ||
|
|
||
| $user = factory(User::class)->make(); | ||
| assert($user instanceof User); | ||
| $user->name = $name; | ||
| $user->save(); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| name: String! | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| name | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'name' => $name, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| public function testLaravelFunctionProperty(): void | ||
| { | ||
| $user = factory(User::class)->create(); | ||
| assert($user instanceof User); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| laravel_function_property: String! | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| laravel_function_property | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'laravel_function_property' => User::FUNCTION_PROPERTY_ATTRIBUTE_VALUE, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| /** @see https://github.com/nuwave/lighthouse/issues/2687 */ | ||
| public function testPhpProperty(): void | ||
| { | ||
| $user = factory(User::class)->create(); | ||
| assert($user instanceof User); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| php_property: String! | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| php_property | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'php_property' => User::PHP_PROPERTY_VALUE, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| /** @see https://github.com/nuwave/lighthouse/issues/2687 */ | ||
| public function testPrefersAttributeAccessorThatShadowsPhpProperty(): void | ||
| { | ||
| $user = factory(User::class)->create(); | ||
| assert($user instanceof User); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| incrementing: String! | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| incrementing | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'incrementing' => User::INCREMENTING_ATTRIBUTE_VALUE, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| /** @see https://github.com/nuwave/lighthouse/issues/2687 */ | ||
| public function testPrefersAttributeAccessorNullThatShadowsPhpProperty(): void | ||
|
Comment on lines
+148
to
+149
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is failing with the current override of the default field resolver, whereas it used to work before. |
||
| { | ||
| $user = factory(User::class)->create(); | ||
| assert($user instanceof User); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| exists: Boolean | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| exists | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'exists' => null, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| /** @see https://github.com/nuwave/lighthouse/issues/1671 */ | ||
| public function testExpensivePropertyIsOnlyCalledOnce(): void | ||
|
Comment on lines
+182
to
+183
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we override the default field resolver, we should also consider this issue and fix it too. |
||
| { | ||
| $user = factory(User::class)->create(); | ||
| assert($user instanceof User); | ||
|
|
||
| $this->schema = /** @lang GraphQL */ <<<GRAPHQL | ||
| type User { | ||
| id: ID! | ||
| expensive_property: Int! | ||
| } | ||
|
|
||
| type Query { | ||
| user(id: ID! @eq): User @find | ||
| } | ||
| GRAPHQL; | ||
|
|
||
| $this->graphQL(/** @lang GraphQL */ ' | ||
| query ($id: ID!) { | ||
| user(id: $id) { | ||
| expensive_property | ||
| } | ||
| } | ||
| ', [ | ||
| 'id' => $user->id, | ||
| ])->assertJson([ | ||
| 'data' => [ | ||
| 'user' => [ | ||
| 'expensive_property' => 1, | ||
| ], | ||
| ], | ||
| ]); | ||
| } | ||
| } | ||
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 we find an implementation that keeps all the tests happy? Or should we bite the bullet and let
testPrefersAttributeAccessorNullThatShadowsPhpPropertyfail?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.
Personally I think having a php property and Laravel-access attribute of the same name is an anti-pattern. I'd even argue that php properties should have priority as that is the way php itself does it. Also they are less computationally expensive to check for presence via
property_exists.The only way to check this would involve checking all the Laravel ways you can define an attribute, not sure if that is worth the effort and extra computation for something that should be evaded in the first place.
Also I don't think such a check can be 100% reliable. While I cannot think of a reason someone would do this, the field could refer to a DB column that isn't selected so it does not appear in
Model::$attributes.Something that might be valuable is adding a check in the maintenance artisan commands that check for name collisions and warn the developer. If for some reason they really need to shadow a php property with a model attribute they can create an accessor with a different name and use
@rename.