feat: AbstractConnectionResolver:set_query_class() created#2821
feat: AbstractConnectionResolver:set_query_class() created#2821kidunot89 wants to merge 9 commits intowp-graphql:developfrom
Conversation
|
First off, love this! (@renatonascalves just suggested something like this so the timing is perfect! ) Couple questions (for context 😬) before I look at the actual code:
The last several attempts at isolated fixes/enhancements to the Connection Resolver all resulted in regressions around cases we don't currently have unit tests for. To try and avoid that from happening again, I've been working to improve the class holistically in #2749 from which we would then backport the individual changes in a nonbreaking manner. My recommendation for this would be the same if it's "just" an enhancement and not tackling a specific regression. |
| * | ||
| * @return void | ||
| */ | ||
| public function set_query_class( $class ) { |
There was a problem hiding this comment.
I've got concerns/questions from a "holistic" POV - nothing that follows should be considering blocking since the same issues exist with the current method of setting the query class via WPConnectionType.
I love the fact that this pattern makes local overloading in a resolver possible, and brings Comment/User connection queries the same extensibility patten, but I'm concerned about its availability on AbstractConnectionResolver, when only 4 (including those in this PR) out of the bundled 13 Connection resolvers actually use a $query_class. Unlike when it was buried in WPConnectionType, the new pattern will see more (mis-)use, so I think it's an opportunity to consider this aspect of the DX.
Similarly, I'm concerned around the lack of checks around the provided $query_class. We dont want to enforce a WP_Query child, but we do need to make sure that the provided class string (SWP_Query, WC_Query, Tribe_Query, FWP_Query, etc etc) is actually compatible with the Connection resolver relying on it.
The latter issue can be solved with an overloadable is_valid_query_class( string $class ) that could for example check for method_exists( $class, 'query' ).
We could even in theory use the same is_valid_query_class() to throw an exception if ! empy( $this->query_class ) on the Connection Resolvers that don't use it (would need to figure out backwards-compatibility), but I think we should first confirm that AbstractConnectionResolver is really the ideal home for this instead of adding what's possibly tech debt to the majority of the included connection resolvers.
There was a problem hiding this comment.
Actually it's more like 6 or 7 out of 13, because they extend one of the 4 connection resolvers and not the AbstractConnectionResolver class directly, Some of them don't even have a get_query() function and default to parent get_query() function in one of the 4. I agree there should be class_exists( $this->query_class ) check somewhere and a is_valid_query_class() function is a good idea. I'll add it immediately.
There was a problem hiding this comment.
because they extend one of the 4 connection resolvers and not the AbstractConnectionResolver class directly, Some of them don't even have a get_query() function and default to parent get_query() function in one of the 4.
Actual numbers aside ☝️is the crux of my concern: we're exposing a setter that semantically should apply on any connection but will be ignored by most of them - something that becomes less obvious from the code the better we are at DRYing out the implementing classes. But I don't have a good alternative 🤔
There was a problem hiding this comment.
The only clean solution I can think of would be make two child classes of the AbstractConnectionResolver that all other extend. One would be something like QueryConnectionResolver and the other would be something like ConnectionResolver. You get the picture 🤷🏿♂️
There was a problem hiding this comment.
Or breaking up AbstractConnectionResolver into traits, but I think either is bad DX in this particular situation since it extenders then need to know which intermediate class / trait is right for a particular WP type, but I don't see a way to have those classes/traits to use existing WP namings. 🤷♂️
There was a problem hiding this comment.
Exactly, but the connection resolvers not using $query_class are highly unlikely to be extended for usage. EnqueuedScripts, EnqueuedStylesheet, Plugin, Taxonomy, Theme, UserRole, and ContentType. So honestly we should be fine.
| public function get_query() { | ||
| return new WP_Comment_Query( $this->query_args ); | ||
| // Get query class. | ||
| $queryClass = ! empty( $this->query_class ) |
There was a problem hiding this comment.
Seeing this alone makes me way happier than it has any right to. 🙌🙌🙌
| $this->assertEquals( 'TestObject', $actual['data']['testConnection']['nodes'][0]['__typename'] ); | ||
| } | ||
|
|
||
| public function testRegisteringConnectionsWithCustomQueryClasses() { |
There was a problem hiding this comment.
We should also have tests for some common edge cases: bad class name, incompatible class, and using the wrong WP_{$type}_Query are the ones that jump to mind.
tests/wpunit/_bootstrap.php
Outdated
| @@ -0,0 +1,3 @@ | |||
| <?php | |||
|
|
|||
| require __DIR__ . '/../_support/Utils/class-wp-query-custom.php'; No newline at end of file | |||
There was a problem hiding this comment.
Can we do this via the autoloader instead?
There was a problem hiding this comment.
Tried too, and it didn't work. It was namespaced and everything. For some reason GraphQL wouldn't see the class and would throw so I eventually devolve into that in the bootstrap file, and I just removed all my PSR dev configuration.
There was a problem hiding this comment.
Feel free to take a crack at after I make your requested changes.
Summarized from a Slack Convo with @kidunot89 (correct me if I made a mistake):
We should probably still address the actual regression in a separate PR. With this in mind, I'm going to port this over to #2749 - even if we don't decide to wait on that PR merging this, I'm betting the effort will still unearth some code suggestions we can implement here independently. |
|
I've updated #2749 to implement this pattern. (If this PR goes forward independently, I highly recommend backporting at least some of the changes). |
- add autoload-dev rule - update namespace for WP_Query_Custom class
|
Code Climate has analyzed commit a74dcb9 and detected 0 issues on this pull request. View more on Code Climate. |
What does this implement/fix? Explain your changes.
While it started as a fix for the
queryClassconnection registration argument which is broken atm of creation in WPGraphQL v1.14.3, this PR ultimately does not fix queryClass but instead make the query class something to be set on the resolver level instead of the registration level. There is some functionality being lost here but it was actually removed a long time ago by @jasonbahl. Then patch back in by myself, @kidunot89, but in a really hacky way. Then broken again by@justlevine. And this will be the introduction of something new but achieves the same desired effect as the
queryClassargument.query_classandset_query_class()to AbstractConnectionResolver class.$query_class.testRegisteringConnectionsWithCustomQueryClassesto theConnectionRegistrationTestcasetests/_support/utils/class-wp-query-custom.phpfor testing.Example registration call using the new functionality.
Does this close any currently open issues?
…
Any relevant logs, error output, GraphiQL screenshots, etc?
(If it’s long, please paste to https://ghostbin.com/ and insert the link here.)
Any other comments?
…
Where has this been tested?
Operating System: …
WordPress Version: …