Skip to content

Commit

Permalink
Merge pull request #3124 from justlevine/dev/refactor-get_args
Browse files Browse the repository at this point in the history
refactor: split `AbstractConnectionResolver::get_args()` and `::get_query_args()` into `::prepare_*()` methods
  • Loading branch information
jasonbahl committed May 8, 2024
2 parents 565137f + b4aad63 commit 6c7cb70
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 156 deletions.
115 changes: 80 additions & 35 deletions src/Data/Connection/AbstractConnectionResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ abstract class AbstractConnectionResolver {
*
* Filterable by `graphql_connection_args`.
*
* @var array<string,mixed>
* @var ?array<string,mixed>
*/
protected $args;

Expand All @@ -57,7 +57,9 @@ abstract class AbstractConnectionResolver {
/**
* The query args used to query for data to resolve the connection.
*
* @var array<string,mixed>
* Filterable by `graphql_connection_query_args`.
*
* @var ?array<string,mixed>
*/
protected $query_args;

Expand Down Expand Up @@ -99,9 +101,9 @@ abstract class AbstractConnectionResolver {
* The Query class/array/object used to fetch the data.
*
* Examples:
* return new WP_Query( $this->query_args );
* return new WP_Comment_Query( $this->query_args );
* return new WP_Term_Query( $this->query_args );
* return new WP_Query( $this->get_query_args() );
* return new WP_Comment_Query( $this->get_query_args() );
* return new WP_Term_Query( $this->get_query_args() );
*
* Whatever it is will be passed through filters so that fields throughout
* have context from what was queried and can make adjustments as needed, such
Expand All @@ -113,6 +115,8 @@ abstract class AbstractConnectionResolver {

/**
* @var mixed[]
*
* @deprecated @todo This is an artifact and is unused. It will be removed in a future release.
*/
protected $items;

Expand Down Expand Up @@ -172,9 +176,9 @@ public function __construct( $source, array $args, AppContext $context, ResolveI

/**
* @todo This exists for b/c, where extenders may be directly accessing `$this->args` in ::get_loader() or even `::get_args()`.
* We can remove this once the rest of lifecycle has been updated.
* We can call it later in the lifecycle once that's no longer the case.
*/
$this->args = $args;
$this->args = $this->get_args();

// Pre-check if the connection should execute so we can skip expensive logic if we already know it shouldn't execute.
if ( ! $this->get_pre_should_execute( $this->source, $this->unfiltered_args, $this->context, $this->info ) ) {
Expand All @@ -185,31 +189,31 @@ public function __construct( $source, array $args, AppContext $context, ResolveI
$this->loader = $this->get_loader();

/**
*
* Filters the GraphQL args before they are used in get_query_args().
*
* @todo We reinstantate this here for b/c. Once that is not a concern, we should relocate this filter to ::get_args().
*
* @param array<string,mixed> $args The GraphQL args passed to the resolver.
* @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver Instance of the ConnectionResolver.
* @param array<string,mixed> $unfiltered_args Array of arguments input in the field as part of the GraphQL query.
*
* @since 1.11.0
*/
$this->args = apply_filters( 'graphql_connection_args', $this->get_args(), $this, $this->get_unfiltered_args() );
$this->args = apply_filters( 'graphql_connection_args', $this->args, $this, $this->get_unfiltered_args() );

// Get the query amount for the connection.
$this->query_amount = $this->get_query_amount();

/**
* Get the Query Args. This accepts the input args and maps it to how it should be
* used in the WP_Query
* Filters the query args before they are used in the query.
*
* Filters the args
* @todo We reinstantate this here for b/c. Once that is not a concern, we should relocate this filter to ::get_query_args().
*
* @param array<string,mixed> $query_args The query args to be used with the executable query to get data.
* @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver Instance of the ConnectionResolver
* @param array<string,mixed> $unfiltered_args Array of arguments input in the field as part of the GraphQL query.
* @param array<string,mixed> $unfiltered_args Array of arguments input in the field as part of the GraphQL query.
*/
$this->query_args = apply_filters( 'graphql_connection_query_args', $this->get_query_args(), $this, $args );
$this->query_args = apply_filters( 'graphql_connection_query_args', $this->get_query_args(), $this, $this->get_unfiltered_args() );
}

/**
Expand All @@ -224,28 +228,30 @@ protected function loader_name(): string {
}

/**
* Returns the $args passed to the connection.
*
* Useful for modifying the $args before they are passed to $this->get_query_args().
* Prepares the query args used to fetch the data for the connection.
*
* @return array<string,mixed>
*/
public function get_args(): array {
return $this->args;
}

/**
* Get_query_args
* This accepts the GraphQL args and maps them to a format that can be read by our query class.
* For example, if the ConnectionResolver uses WP_Query to fetch the data, this should return $args for use in `new WP_Query( $args );`
*
* This method is used to accept the GraphQL Args input to the connection and return args
* that can be used in the Query to the datasource.
* @todo This is protected for backwards compatibility, but should be abstract and implemented by the child classes.
*
* For example, if the ConnectionResolver uses WP_Query to fetch the data, this
* should return $args for use in `new WP_Query`
* @param array<string,mixed> $args The GraphQL input args passed to the connection.
*
* @return array<string,mixed>
*
* @throws \Exception If the method is not implemented.
*
* @codeCoverageIgnore
*/
abstract public function get_query_args();
protected function prepare_query_args( array $args ): array {
throw new Exception(
sprintf(
// translators: %s is the name of the connection resolver class.
esc_html__( 'Class %s does not implement a valid method `prepare_query_args()`.', 'wp-graphql' ),
static::class
)
);
}

/**
* Get_query
Expand Down Expand Up @@ -296,6 +302,19 @@ protected function pre_should_execute( $source, array $args, AppContext $context
return $should_execute;
}

/**
* Prepares the GraphQL args for use by the connection.
*
* Useful for modifying the $args before they are passed to $this->get_query_args().
*
* @param array<string,mixed> $args The GraphQL input args to prepare.
*
* @return array<string,mixed>
*/
protected function prepare_args( array $args ): array {
return $args;
}

/**
* The maximum number of items that should be returned by the query.
*
Expand All @@ -311,7 +330,7 @@ protected function max_query_amount(): int {
* Each Query class in WP and potential datasource handles this differently, so each connection
* resolver should handle getting the items into a uniform array of items.
*
* Note: This is not an abstract function to prevent backwards compatibility issues, so it
* @todo: This is not an abstract function to prevent backwards compatibility issues, so it
* instead throws an exception. Classes that extend AbstractConnectionResolver should
* override this method, instead of AbstractConnectionResolver::get_ids().
*
Expand Down Expand Up @@ -456,7 +475,6 @@ public function get_loader_name() {
return $this->loader_name;
}


/**
* Returns the $args passed to the connection, before any modifications.
*
Expand All @@ -466,6 +484,19 @@ public function get_unfiltered_args(): array {
return $this->unfiltered_args;
}

/**
* Returns the $args passed to the connection.
*
* @return array<string,mixed>
*/
public function get_args(): array {
if ( ! isset( $this->args ) ) {
$this->args = $this->prepare_args( $this->get_unfiltered_args() );
}

return $this->args;
}

/**
* Returns the amount of items to query from the database.
*
Expand All @@ -491,7 +522,7 @@ public function get_query_amount() {
*
* @since 0.0.6
*/
$max_query_amount = (int) apply_filters( 'graphql_connection_max_query_amount', $this->max_query_amount(), $this->source, $this->args, $this->context, $this->info );
$max_query_amount = (int) apply_filters( 'graphql_connection_max_query_amount', $this->max_query_amount(), $this->source, $this->get_args(), $this->context, $this->info );

// We don't want the requested amount to be lower than 0.
$requested_query_amount = (int) max(
Expand All @@ -518,6 +549,20 @@ public function get_query_amount() {
return $this->query_amount;
}

/**
* Gets the query args used by the connection to fetch the data.
*
* @return array<string,mixed>
*/
public function get_query_args() {
if ( ! isset( $this->query_args ) ) {
// We pass $this->get_args() to ensure we're using the filtered args.
$this->query_args = $this->prepare_query_args( $this->get_args() );
}

return $this->query_args;
}

/**
* Returns whether the connection should execute.
*
Expand Down Expand Up @@ -807,8 +852,8 @@ function () {
*
* This filter allows additional fields to be returned to the connection resolver
*
* @param ?array<string,mixed> $connection The connection data being returned. A single edge or null if the connection is one-to-one.
* @param self $resolver The instance of the connection resolver
* @param ?array<string,mixed> $connection The connection data being returned. A single edge or null if the connection is one-to-one.
* @param self $resolver The instance of the connection resolver
*/
return apply_filters( 'graphql_connection', $connection, $this );
}
Expand Down
44 changes: 20 additions & 24 deletions src/Data/Connection/CommentConnectionResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ class CommentConnectionResolver extends AbstractConnectionResolver {
*
* @throws \GraphQL\Error\UserError
*/
public function get_query_args() {

protected function prepare_query_args( array $args ): array {
/**
* Prepare for later use
*/
$last = ! empty( $this->args['last'] ) ? $this->args['last'] : null;
$last = ! empty( $args['last'] ) ? $args['last'] : null;

$query_args = [];

Expand All @@ -56,18 +55,18 @@ public function get_query_args() {
$query_args['orderby'] = 'comment_date';

/**
* Take any of the $this->args that were part of the GraphQL query and map their
* Take any of the $args that were part of the GraphQL query and map their
* GraphQL names to the WP_Term_Query names to be used in the WP_Term_Query
*
* @since 0.0.5
*/
$input_fields = [];
if ( ! empty( $this->args['where'] ) ) {
$input_fields = $this->sanitize_input_fields( $this->args['where'] );
if ( ! empty( $args['where'] ) ) {
$input_fields = $this->sanitize_input_fields( $args['where'] );
}

/**
* Merge the default $query_args with the $this->args that were entered
* Merge the default $query_args with the $args that were entered
* in the query.
*
* @since 0.0.5
Expand Down Expand Up @@ -113,14 +112,14 @@ public function get_query_args() {
$query_args['graphql_before_cursor'] = $this->get_before_offset();

/**
* Pass the graphql $this->args to the WP_Query
* Pass the graphql $args to the WP_Query
*/
$query_args['graphql_args'] = $this->args;
$query_args['graphql_args'] = $args;

// encode the graphql args as a cache domain to ensure the
// graphql_args are used to identify different queries.
// see: https://core.trac.wordpress.org/ticket/35075
$encoded_args = wp_json_encode( $this->args );
$encoded_args = wp_json_encode( $args );
$query_args['cache_domain'] = ! empty( $encoded_args ) ? 'graphql:' . md5( $encoded_args ) : 'graphql';

/**
Expand All @@ -130,8 +129,7 @@ public function get_query_args() {
$query_args['fields'] = 'ids';

/**
* Filter the query_args that should be applied to the query. This filter is applied AFTER the input args from
* the GraphQL Query have been applied and has the potential to override the GraphQL Query Input Args.
* Filter the query_args that should be applied to the query.
*
* @param array<string,mixed> $query_args array of query_args being passed to the
* @param mixed $source source passed down from the resolve tree
Expand All @@ -141,7 +139,7 @@ public function get_query_args() {
*
* @since 0.0.6
*/
return apply_filters( 'graphql_comment_connection_query_args', $query_args, $this->source, $this->args, $this->context, $this->info );
return apply_filters( 'graphql_comment_connection_query_args', $query_args, $this->source, $args, $this->context, $this->info );
}

/**
Expand All @@ -151,7 +149,7 @@ public function get_query_args() {
* @throws \Exception
*/
public function get_query() {
return new WP_Comment_Query( $this->query_args );
return new WP_Comment_Query( $this->get_query_args() );
}

/**
Expand All @@ -169,21 +167,19 @@ public function get_ids_from_query() {
$ids = ! empty( $this->query->get_comments() ) ? $this->query->get_comments() : [];

// If we're going backwards, we need to reverse the array.
if ( ! empty( $this->args['last'] ) ) {
$args = $this->get_args();

if ( ! empty( $args['last'] ) ) {
$ids = array_reverse( $ids );
}

return $ids;
}

/**
* Filters the GraphQL args before they are used in get_query_args().
*
* @return array<string,mixed>
* {@inheritDoc}
*/
public function get_args(): array {
$args = $this->get_unfiltered_args();

protected function prepare_args( array $args ): array {
if ( ! empty( $args['where'] ) ) {
// Ensure all IDs are converted to database IDs.
foreach ( $args['where'] as $input_key => $input_value ) {
Expand Down Expand Up @@ -238,8 +234,8 @@ static function ( $id ) {
/**
* Filters the GraphQL args before they are used in get_query_args().
*
* @param array<string,mixed> $args The GraphQL args passed to the resolver.
* @param \WPGraphQL\Data\Connection\CommentConnectionResolver $connection_resolver Instance of the ConnectionResolver
* @param array<string,mixed> $args The GraphQL args passed to the resolver.
* @param self $resolver Instance of the ConnectionResolver
*
* @since 1.11.0
*/
Expand Down Expand Up @@ -298,7 +294,7 @@ public function sanitize_input_fields( array $args ) {
*
* @since 0.0.5
*/
$query_args = apply_filters( 'graphql_map_input_fields_to_wp_comment_query', $query_args, $args, $this->source, $this->args, $this->context, $this->info );
$query_args = apply_filters( 'graphql_map_input_fields_to_wp_comment_query', $query_args, $args, $this->source, $this->get_args(), $this->context, $this->info );

return ! empty( $query_args ) && is_array( $query_args ) ? $query_args : [];
}
Expand Down
13 changes: 7 additions & 6 deletions src/Data/Connection/ContentTypeConnectionResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function get_ids_from_query() {
/**
* {@inheritDoc}
*/
public function get_query_args() {
protected function prepare_query_args( array $args ): array {
// If any args are added to filter/sort the connection
return [];
}
Expand All @@ -46,15 +46,16 @@ public function get_query_args() {
* @return string[]
*/
public function get_query() {
if ( isset( $this->query_args['contentTypeNames'] ) && is_array( $this->query_args['contentTypeNames'] ) ) {
return $this->query_args['contentTypeNames'];
$query_args = $this->get_query_args();

if ( isset( $query_args['contentTypeNames'] ) && is_array( $query_args['contentTypeNames'] ) ) {
return $query_args['contentTypeNames'];
}

if ( isset( $this->query_args['name'] ) ) {
return [ $this->query_args['name'] ];
if ( isset( $query_args['name'] ) ) {
return [ $query_args['name'] ];
}

$query_args = $this->query_args;
return \WPGraphQL::get_allowed_post_types( 'names', $query_args );
}

Expand Down

0 comments on commit 6c7cb70

Please sign in to comment.