From 1f8ed88c32f25c8ec90346d3251b74f298f06643 Mon Sep 17 00:00:00 2001 From: Geoff Taylor Date: Wed, 13 Sep 2023 11:18:10 -0400 Subject: [PATCH] feat: CartItem converted to WPInterface type --- includes/class-type-registry.php | 1 + includes/class-wp-graphql-woocommerce.php | 1 + includes/type/interface/class-cart-item.php | 306 ++++++++++++++++++++ includes/type/object/class-cart-type.php | 245 ---------------- 4 files changed, 308 insertions(+), 245 deletions(-) create mode 100644 includes/type/interface/class-cart-item.php diff --git a/includes/class-type-registry.php b/includes/class-type-registry.php index da7af873..212177e1 100644 --- a/includes/class-type-registry.php +++ b/includes/class-type-registry.php @@ -70,6 +70,7 @@ public function init() { Type\WPInterface\Cart_Error::register_interface(); Type\WPInterface\Payment_Token::register_interface(); Type\WPInterface\Product_Union::register_interface(); + Type\WPInterface\Cart_Item::register_interface(); /** * Objects. diff --git a/includes/class-wp-graphql-woocommerce.php b/includes/class-wp-graphql-woocommerce.php index 929941a9..fed600aa 100644 --- a/includes/class-wp-graphql-woocommerce.php +++ b/includes/class-wp-graphql-woocommerce.php @@ -244,6 +244,7 @@ private function includes() { require $include_directory_path . 'type/interface/class-product.php'; require $include_directory_path . 'type/interface/class-payment-token.php'; require $include_directory_path . 'type/interface/class-product-union.php'; + require $include_directory_path . 'type/interface/class-cart-item.php'; // Include object type class files. require $include_directory_path . 'type/object/class-cart-error-types.php'; diff --git a/includes/type/interface/class-cart-item.php b/includes/type/interface/class-cart-item.php new file mode 100644 index 00000000..36657bce --- /dev/null +++ b/includes/type/interface/class-cart-item.php @@ -0,0 +1,306 @@ + __( 'Cart item interface.', 'wp-graphql-woocommerce' ), + 'interfaces' => [ 'Node' ], + 'fields' => self::get_fields(), + 'connections' => self::get_connections(), + 'resolveType' => static function ( $cart_item ) { + /** + * Instance of the WPGraphQL TypeRegistry. + * + * @var \WPGraphQL\Registry\TypeRegistry $type_registry + */ + $type_registry = \WPGraphQL::get_type_registry(); + + $type_name = apply_filters( 'woographql_cart_item_type', 'SimpleCartItem', $cart_item ); + if ( empty( $type_name ) ) { + throw new UserError( __( 'Invalid cart item type provided.', 'wp-graphql-woocommerce' ) ); + } + + return $type_registry->get_type( $type_name ); + }, + ] + ); + + register_graphql_object_type( + 'SimpleCartItem', + [ + 'eagerlyLoadType' => true, + 'description' => __( 'A item in the cart', 'wp-graphql-woocommerce' ), + 'interfaces' => [ 'Node', 'CartItem' ], + 'fields' => [], + ] + ); + } + + /** + * Returns common cart field definitions. + * + * @return array + */ + public static function get_fields() { + return [ + 'key' => [ + 'type' => [ 'non_null' => 'ID' ], + 'description' => __( 'CartItem ID', 'wp-graphql-woocommerce' ), + 'resolve' => static function ( $source ) { + return ! empty( $source['key'] ) ? $source['key'] : null; + }, + ], + 'quantity' => [ + 'type' => 'Int', + 'description' => __( 'Quantity of the product', 'wp-graphql-woocommerce' ), + 'resolve' => static function ( $source ) { + return isset( $source['quantity'] ) ? absint( $source['quantity'] ) : null; + }, + ], + 'subtotal' => [ + 'type' => 'String', + 'description' => __( 'Item\'s subtotal', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => static function ( $source, array $args ) { + $price = isset( $source['line_subtotal'] ) ? floatval( $source['line_subtotal'] ) : 0; + + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } + + return \wc_graphql_price( $price ); + }, + ], + 'subtotalTax' => [ + 'type' => 'String', + 'description' => __( 'Item\'s subtotal tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => static function ( $source, array $args ) { + $price = isset( $source['line_subtotal_tax'] ) ? floatval( $source['line_subtotal_tax'] ) : 0; + + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } + + return \wc_graphql_price( $price ); + }, + ], + 'total' => [ + 'type' => 'String', + 'description' => __( 'Item\'s total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => static function ( $source, array $args ) { + $price_without_tax = isset( $source['line_total'] ) ? floatval( $source['line_total'] ) : 0; + $tax = isset( $source['line_tax'] ) ? floatval( $source['line_tax'] ) : 0; + $price = $price_without_tax + $tax; + + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } + + return \wc_graphql_price( $price ); + }, + ], + 'tax' => [ + 'type' => 'String', + 'description' => __( 'Item\'s tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => static function ( $source, array $args ) { + $price = isset( $source['line_tax'] ) ? floatval( $source['line_tax'] ) : 0; + + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } + + return \wc_graphql_price( $price ); + }, + ], + 'extraData' => [ + 'type' => [ 'list_of' => 'MetaData' ], + 'description' => __( 'Object meta data', 'wp-graphql-woocommerce' ), + 'args' => [ + 'key' => [ + 'type' => 'String', + 'description' => __( 'Retrieve meta by key', 'wp-graphql-woocommerce' ), + ], + 'keysIn' => [ + 'type' => [ 'list_of' => 'String' ], + 'description' => __( 'Retrieve multiple metas by key', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => static function ( $source, array $args ) { + // Check if "key" argument set and assigns to target "keys" array. + if ( ! empty( $args['key'] ) && ! empty( $source[ $args['key'] ] ) ) { + $keys = [ $args['key'] ]; + } elseif ( ! empty( $args['keysIn'] ) ) { + // Check if "keysIn" argument set and assigns to target "keys" array. + $keys = []; + foreach ( $args['keysIn'] as $key ) { + if ( ! empty( $source[ $key ] ) ) { + $keys[] = $key; + } + } + } else { + // If no arguments set, all extra data keys are assigns to target "keys" array. + $keys = array_diff( + array_keys( $source ), + [ + 'key', + 'product_id', + 'variation_id', + 'variation', + 'quantity', + 'data', + 'data_hash', + 'line_tax_data', + 'line_subtotal', + 'line_subtotal_tax', + 'line_total', + 'line_tax', + ] + ); + }//end if + // Create meta ID prefix. + $id_prefix = apply_filters( 'graphql_woocommerce_cart_meta_id_prefix', 'cart_' ); + + // Format meta data for resolution. + $data = []; + foreach ( $keys as $key ) { + $data[] = (object) [ + 'id' => "{$id_prefix}_{$key}", + 'key' => $key, + 'value' => is_array( $source[ $key ] ) ? wp_json_encode( $source[ $key ] ) : $source[ $key ], + ]; + } + + return $data; + }, + ], + ]; + } + + /** + * Defines connections. + * + * @return array + */ + public static function get_connections() { + return [ + 'product' => [ + 'toType' => 'Product', + 'oneToOne' => true, + 'edgeFields' => [ + 'simpleVariations' => [ + 'type' => [ 'list_of' => 'SimpleAttribute' ], + 'description' => __( 'Simple variation attribute data', 'wp-graphql-woocommerce' ), + 'resolve' => static function ( $source ) { + $attributes = []; + + $variation = $source['node']; + $cart_item_data = $source['source']; + $simple_attribute_data = $cart_item_data['variation']; + foreach ( $simple_attribute_data as $name => $value ) { + $attributes[] = compact( 'name', 'value' ); + } + + return $attributes; + }, + ], + ], + 'resolve' => static function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + $id = $source['product_id']; + $resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product' ); + + return $resolver + ->one_to_one() + ->set_query_arg( 'p', $id ) + ->get_connection(); + }, + ], + 'variation' => [ + 'toType' => 'ProductVariation', + 'oneToOne' => true, + 'edgeFields' => [ + 'attributes' => [ + 'type' => [ 'list_of' => 'VariationAttribute' ], + 'description' => __( 'Attributes of the variation.', 'wp-graphql-woocommerce' ), + 'resolve' => static function ( $source ) { + $attributes = []; + + $variation = $source['node']; + $cart_item_data = $source['source']; + $cart_variation_data = $cart_item_data['variation']; + foreach ( $variation->attributes as $name => $default_value ) { + if ( isset( $cart_variation_data[ "attribute_{$name}" ] ) ) { + $attributes[ $name ] = $cart_variation_data[ "attribute_{$name}" ]; + } else { + $attributes[ $name ] = $default_value; + } + } + + return Variation_Attribute_Connection_Resolver::variation_attributes_to_data_array( $attributes, $variation->ID ); + }, + ], + ], + 'resolve' => static function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + $id = ! empty( $source['variation_id'] ) ? $source['variation_id'] : null; + $resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product_variation' ); + + if ( ! $id ) { + return null; + } + + return $resolver + ->one_to_one() + ->set_query_arg( 'p', $id ) + ->get_connection(); + }, + ], + ]; + } +} diff --git a/includes/type/object/class-cart-type.php b/includes/type/object/class-cart-type.php index 7c734027..2947b7f7 100644 --- a/includes/type/object/class-cart-type.php +++ b/includes/type/object/class-cart-type.php @@ -12,9 +12,7 @@ use GraphQL\Type\Definition\ResolveInfo; use WPGraphQL\AppContext; -use WPGraphQL\Data\Connection\PostObjectConnectionResolver; use WPGraphQL\WooCommerce\Data\Connection\Cart_Item_Connection_Resolver; -use WPGraphQL\WooCommerce\Data\Connection\Variation_Attribute_Connection_Resolver; use WPGraphQL\WooCommerce\Data\Factory; /** @@ -30,7 +28,6 @@ public static function register() { self::register_cart_fee(); self::register_cart_tax(); self::register_applied_coupon(); - self::register_cart_item(); self::register_cart(); } @@ -464,248 +461,6 @@ public static function register_cart() { ); } - /** - * Registers CartItem type - * - * @return void - */ - public static function register_cart_item() { - register_graphql_object_type( - 'CartItem', - [ - 'description' => __( 'A item in the cart', 'wp-graphql-woocommerce' ), - 'interfaces' => [ 'Node' ], - 'fields' => [ - 'key' => [ - 'type' => [ 'non_null' => 'ID' ], - 'description' => __( 'CartItem ID', 'wp-graphql-woocommerce' ), - 'resolve' => static function ( $source ) { - return ! empty( $source['key'] ) ? $source['key'] : null; - }, - ], - 'quantity' => [ - 'type' => 'Int', - 'description' => __( 'Quantity of the product', 'wp-graphql-woocommerce' ), - 'resolve' => static function ( $source ) { - return isset( $source['quantity'] ) ? absint( $source['quantity'] ) : null; - }, - ], - 'subtotal' => [ - 'type' => 'String', - 'description' => __( 'Item\'s subtotal', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => static function ( $source, array $args ) { - $price = isset( $source['line_subtotal'] ) ? floatval( $source['line_subtotal'] ) : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return wc_graphql_price( $price ); - }, - ], - 'subtotalTax' => [ - 'type' => 'String', - 'description' => __( 'Item\'s subtotal tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => static function ( $source, array $args ) { - $price = isset( $source['line_subtotal_tax'] ) ? floatval( $source['line_subtotal_tax'] ) : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return wc_graphql_price( $price ); - }, - ], - 'total' => [ - 'type' => 'String', - 'description' => __( 'Item\'s total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => static function ( $source, array $args ) { - $price_without_tax = isset( $source['line_total'] ) ? floatval( $source['line_total'] ) : 0; - $tax = isset( $source['line_tax'] ) ? floatval( $source['line_tax'] ) : 0; - $price = $price_without_tax + $tax; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return wc_graphql_price( $price ); - }, - ], - 'tax' => [ - 'type' => 'String', - 'description' => __( 'Item\'s tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => static function ( $source, array $args ) { - $price = isset( $source['line_tax'] ) ? floatval( $source['line_tax'] ) : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return wc_graphql_price( $price ); - }, - ], - 'extraData' => [ - 'type' => [ 'list_of' => 'MetaData' ], - 'description' => __( 'Object meta data', 'wp-graphql-woocommerce' ), - 'args' => [ - 'key' => [ - 'type' => 'String', - 'description' => __( 'Retrieve meta by key', 'wp-graphql-woocommerce' ), - ], - 'keysIn' => [ - 'type' => [ 'list_of' => 'String' ], - 'description' => __( 'Retrieve multiple metas by key', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => static function ( $source, array $args ) { - // Check if "key" argument set and assigns to target "keys" array. - if ( ! empty( $args['key'] ) && ! empty( $source[ $args['key'] ] ) ) { - $keys = [ $args['key'] ]; - } elseif ( ! empty( $args['keysIn'] ) ) { - // Check if "keysIn" argument set and assigns to target "keys" array. - $keys = []; - foreach ( $args['keysIn'] as $key ) { - if ( ! empty( $source[ $key ] ) ) { - $keys[] = $key; - } - } - } else { - // If no arguments set, all extra data keys are assigns to target "keys" array. - $keys = array_diff( - array_keys( $source ), - [ - 'key', - 'product_id', - 'variation_id', - 'variation', - 'quantity', - 'data', - 'data_hash', - 'line_tax_data', - 'line_subtotal', - 'line_subtotal_tax', - 'line_total', - 'line_tax', - ] - ); - }//end if - // Create meta ID prefix. - $id_prefix = apply_filters( 'graphql_woocommerce_cart_meta_id_prefix', 'cart_' ); - - // Format meta data for resolution. - $data = []; - foreach ( $keys as $key ) { - $data[] = (object) [ - 'id' => "{$id_prefix}_{$key}", - 'key' => $key, - 'value' => is_array( $source[ $key ] ) ? wp_json_encode( $source[ $key ] ) : $source[ $key ], - ]; - } - - return $data; - }, - ], - ], - 'connections' => [ - 'product' => [ - 'toType' => 'Product', - 'oneToOne' => true, - 'edgeFields' => [ - 'simpleVariations' => [ - 'type' => [ 'list_of' => 'SimpleAttribute' ], - 'description' => __( 'Simple variation attribute data', 'wp-graphql-woocommerce' ), - 'resolve' => static function ( $source ) { - $attributes = []; - - $variation = $source['node']; - $cart_item_data = $source['source']; - $simple_attribute_data = $cart_item_data['variation']; - foreach ( $simple_attribute_data as $name => $value ) { - $attributes[] = compact( 'name', 'value' ); - } - - return $attributes; - }, - ], - ], - 'resolve' => static function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $id = $source['product_id']; - $resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product' ); - - return $resolver - ->one_to_one() - ->set_query_arg( 'p', $id ) - ->get_connection(); - }, - ], - 'variation' => [ - 'toType' => 'ProductVariation', - 'oneToOne' => true, - 'edgeFields' => [ - 'attributes' => [ - 'type' => [ 'list_of' => 'VariationAttribute' ], - 'description' => __( 'Attributes of the variation.', 'wp-graphql-woocommerce' ), - 'resolve' => static function ( $source ) { - $attributes = []; - - $variation = $source['node']; - $cart_item_data = $source['source']; - $cart_variation_data = $cart_item_data['variation']; - foreach ( $variation->attributes as $name => $default_value ) { - if ( isset( $cart_variation_data[ "attribute_{$name}" ] ) ) { - $attributes[ $name ] = $cart_variation_data[ "attribute_{$name}" ]; - } else { - $attributes[ $name ] = $default_value; - } - } - - return Variation_Attribute_Connection_Resolver::variation_attributes_to_data_array( $attributes, $variation->ID ); - }, - ], - ], - 'resolve' => static function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $id = $source['variation_id']; - $resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product_variation' ); - - if ( ! $id ) { - return null; - } - - return $resolver - ->one_to_one() - ->set_query_arg( 'p', $id ) - ->get_connection(); - }, - ], - ], - ] - ); - } - /** * Registers CartFee type *