From 43d529f78f2e5cc3f3df7cd782c4c3637655c525 Mon Sep 17 00:00:00 2001 From: Geoff Taylor Date: Fri, 24 Jan 2020 23:40:50 -0500 Subject: [PATCH 1/2] "idType" implemented. --- README.txt | 2 +- includes/class-type-registry.php | 1 + includes/type/enum/class-id-type-enums.php | 132 ++++++++++++++++++ includes/type/interface/class-product.php | 100 +++++++++---- includes/type/object/class-coupon-type.php | 105 ++++++++++---- includes/type/object/class-order-type.php | 67 ++++++--- includes/type/object/class-product-types.php | 105 +++++++++++--- .../object/class-product-variation-type.php | 57 +++++--- includes/type/object/class-refund-type.php | 87 ++++++------ tests/wpunit/CouponQueriesTest.php | 54 +++++-- tests/wpunit/MetaDataQueriesTest.php | 3 +- tests/wpunit/OrderQueriesTest.php | 48 +++++-- tests/wpunit/ProductQueriesTest.php | 62 ++++++-- tests/wpunit/ProductVariationQueriesTest.php | 33 +++-- tests/wpunit/RefundQueriesTest.php | 26 ++-- vendor/autoload.php | 2 +- vendor/composer/autoload_classmap.php | 1 + vendor/composer/autoload_real.php | 14 +- vendor/composer/autoload_static.php | 9 +- wp-graphql-woocommerce.php | 4 +- 20 files changed, 685 insertions(+), 227 deletions(-) create mode 100644 includes/type/enum/class-id-type-enums.php diff --git a/README.txt b/README.txt index 33bb5e780..35c2d04ba 100644 --- a/README.txt +++ b/README.txt @@ -7,7 +7,7 @@ Requires PHP: 5.6 Requires WooCommerce: 3.0.0 Requires WPGraphQL: 0.6.0+ Works with WPGraphQL-JWT-Authentication: 0.4.0+ -Stable tag: 0.4.0 +Stable tag: 0.4.1 License: GPL-3 License URI: https://www.gnu.org/licenses/gpl-3.0.html Maintained at: https://github.com/wp-graphql/wp-graphql-woocommerce diff --git a/includes/class-type-registry.php b/includes/class-type-registry.php index 060bf0e26..7466a1306 100644 --- a/includes/class-type-registry.php +++ b/includes/class-type-registry.php @@ -38,6 +38,7 @@ public function init( \WPGraphQL\Registry\TypeRegistry $type_registry ) { \WPGraphQL\WooCommerce\Type\WPEnum\Post_Type_Orderby_Enum::register(); \WPGraphQL\WooCommerce\Type\WPEnum\Products_Orderby_Enum::register(); \WPGraphQL\WooCommerce\Type\WPEnum\Orders_Orderby_Enum::register(); + \WPGraphQL\WooCommerce\Type\WPEnum\Id_Type_Enums::register(); // InputObjects. \WPGraphQL\WooCommerce\Type\WPInputObject\Customer_Address_Input::register(); diff --git a/includes/type/enum/class-id-type-enums.php b/includes/type/enum/class-id-type-enums.php new file mode 100644 index 000000000..151a79e1c --- /dev/null +++ b/includes/type/enum/class-id-type-enums.php @@ -0,0 +1,132 @@ + __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + 'code' => array( + 'name' => 'CODE', + 'value' => 'code', + 'description' => __( 'Coupon code.', 'wp-graphql-woocommerce' ), + ), + ), + ) + ); + + register_graphql_enum_type( + 'OrderIdTypeEnum', + array( + 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + 'order_number' => array( + 'name' => 'ORDER_NUMBER', + 'value' => 'order_number', + 'description' => __( 'Order number.', 'wp-graphql-woocommerce' ), + ), + ), + ) + ); + + register_graphql_enum_type( + 'ProductIdTypeEnum', + array( + 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + 'slug' => self::get_value( 'slug' ), + 'sku' => array( + 'name' => 'SKU', + 'value' => 'sku', + 'description' => __( 'Unique store identifier for product.', 'wp-graphql-woocommerce' ), + ), + ), + ) + ); + + register_graphql_enum_type( + 'ProductVariationIdTypeEnum', + array( + 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + ), + ) + ); + + register_graphql_enum_type( + 'RefundIdTypeEnum', + array( + 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + ), + ) + ); + } + + /** + * Returns Enum Value definition. + * + * @param string $value Enumeration value being retrieved. + * @return array + */ + private static function get_value( $value ) { + switch ( $value ) { + case 'slug': + return array( + 'name' => 'SLUG', + 'value' => 'slug', + 'description' => __( + 'Identify a resource by the slug. Available to non-hierarchcial Types where the slug is a unique identifier.', + 'wp-graphql-woocommerce' + ), + ); + case 'id': + return array( + 'name' => 'ID', + 'value' => 'global_id', + 'description' => __( 'Identify a resource by the (hashed) Global ID.', 'wp-graphql-woocommerce' ), + ); + case 'database_id': + return array( + 'name' => 'DATABASE_ID', + 'value' => 'database_id', + 'description' => __( 'Identify a resource by the Database ID.', 'wp-graphql-woocommerce' ), + ); + case 'uri': + return array( + 'name' => 'URI', + 'value' => 'uri', + 'description' => __( 'Identify a resource by the URI.', 'wp-graphql-woocommerce' ), + ); + } + } +} diff --git a/includes/type/interface/class-product.php b/includes/type/interface/class-product.php index 9d27c5cbe..8c3205964 100644 --- a/includes/type/interface/class-product.php +++ b/includes/type/interface/class-product.php @@ -55,48 +55,90 @@ public static function register_interface( &$type_registry ) { 'type' => 'Product', 'description' => __( 'A product object', 'wp-graphql-woocommerce' ), 'args' => array( - 'id' => array( + 'id' => array( 'type' => array( 'non_null' => 'ID' ), ), + 'idType' => array( + 'type' => 'ProductIdTypeEnum', + 'description' => __( 'Type of ID being used identify product', 'wp-graphql-woocommerce' ), + ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( ! isset( $id_components['id'] ) || ! absint( $id_components['id'] ) ) { - throw new UserError( __( 'The ID input is invalid', 'wp-graphql-woocommerce' ) ); + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + $product_id = null; + switch ( $id_type ) { + case 'sku': + $product_id = \wc_get_product_id_by_sku( $id ); + break; + case 'slug': + $post = get_page_by_path( $id, OBJECT, 'product' ); + $product_id = ! empty( $post ) ? absint( $post->ID ) : 0; + break; + case 'database_id': + $product_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "global ID" is invalid', 'wp-graphql-woocommerce' ) ); + } + $product_id = absint( $id_components['id'] ); + break; + } + + if ( empty( $product_id ) ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No product ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); + } elseif ( get_post( $product_id )->post_type !== 'product' ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No product exists with the %1$s: %2$s' ), $id_type, $id ) ); } - $product_id = absint( $id_components['id'] ); - return Factory::resolve_crud_object( $product_id, $context ); + + $product = Factory::resolve_crud_object( $product_id, $context ); + + return $product; }, ) ); - $post_by_args = array( - 'id' => array( - 'type' => 'ID', - 'description' => __( 'Get the product by its global ID', 'wp-graphql-woocommerce' ), - ), - 'productId' => array( - 'type' => 'Int', - 'description' => __( 'Get the product by its database ID', 'wp-graphql-woocommerce' ), - ), - 'slug' => array( - 'type' => 'String', - 'description' => __( 'Get the product by its slug', 'wp-graphql-woocommerce' ), - ), - 'sku' => array( - 'type' => 'String', - 'description' => __( 'Get the product by its sku', 'wp-graphql-woocommerce' ), - ), - ); - + /** + * DEPRECATED + * + * Will be removed in v0.5.x. + */ register_graphql_field( 'RootQuery', 'productBy', array( - 'type' => 'Product', - 'description' => __( 'A product object', 'wp-graphql-woocommerce' ), - 'args' => $post_by_args, - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + 'type' => 'Product', + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This query has been deprecation, and will be removed in v0.5.x. Please use "product(id: value, idType: DATABASE_ID|SLUG|SKU)" instead', + 'wp-graphql-woocommerce' + ), + 'description' => __( 'A product object', 'wp-graphql-woocommerce' ), + 'args' => array( + 'id' => array( + 'type' => 'ID', + 'description' => __( 'Get the product by its global ID', 'wp-graphql-woocommerce' ), + ), + 'productId' => array( + 'type' => 'Int', + 'description' => __( 'Get the product by its database ID', 'wp-graphql-woocommerce' ), + ), + 'slug' => array( + 'type' => 'String', + 'description' => __( 'Get the product by its slug', 'wp-graphql-woocommerce' ), + ), + 'sku' => array( + 'type' => 'String', + 'description' => __( 'Get the product by its sku', 'wp-graphql-woocommerce' ), + ), + ), + 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { $product_id = 0; $id_type = ''; if ( ! empty( $args['id'] ) ) { diff --git a/includes/type/object/class-coupon-type.php b/includes/type/object/class-coupon-type.php index 70c29ece4..ac80c3aa0 100644 --- a/includes/type/object/class-coupon-type.php +++ b/includes/type/object/class-coupon-type.php @@ -119,66 +119,111 @@ public static function register() { 'type' => 'Coupon', 'description' => __( 'A coupon object', 'wp-graphql-woocommerce' ), 'args' => array( - 'id' => array( + 'id' => array( 'type' => array( 'non_null' => 'ID', ), ), + 'idType' => array( + 'type' => 'CouponIdTypeEnum', + 'description' => __( 'Type of ID being used identify coupon', 'wp-graphql-woocommerce' ), + ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( ! isset( $id_components['id'] ) || ! absint( $id_components['id'] ) ) { - throw new UserError( __( 'The ID input is invalid', 'wp-graphql-woocommerce' ) ); + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + $coupon_id = null; + switch ( $id_type ) { + case 'code': + $coupon_id = \wc_get_coupon_id_by_code( $id ); + break; + case 'database_id': + $coupon_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $args['id'] ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $coupon_id = absint( $id_components['id'] ); + break; } - $coupon_id = absint( $id_components['id'] ); + + if ( empty( $coupon_id ) ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No coupon ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); + } elseif ( get_post( $coupon_id )->post_type !== 'shop_coupon' ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No coupon exists with the %1$s: %2$s' ), $id_type, $id ) ); + } + return Factory::resolve_crud_object( $coupon_id, $context ); }, ) ); - $post_by_args = array( - 'id' => array( - 'type' => 'ID', - 'description' => __( 'Get the coupon by its global ID', 'wp-graphql-woocommerce' ), - ), - 'couponId' => array( - 'type' => 'Int', - 'description' => __( 'Get the coupon by its database ID', 'wp-graphql-woocommerce' ), - ), - 'code' => array( - 'type' => 'String', - 'description' => __( 'Get the coupon by its code', 'wp-graphql-woocommerce' ), - ), - ); - + /** + * DEPRECATED + * + * Will be removed in v0.5.x. + */ register_graphql_field( 'RootQuery', 'couponBy', array( - 'type' => 'Coupon', - 'description' => __( 'A coupon object', 'wp-graphql-woocommerce' ), - 'args' => $post_by_args, - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $coupon_id = 0; + 'type' => 'Coupon', + 'description' => __( 'A coupon object', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This query has been deprecation, and will be removed in v0.5.x. Please use "coupon(id: value, idType: DATABASE_ID|CODE)" instead', + 'wp-graphql-woocommerce' + ), + 'args' => array( + 'id' => array( + 'type' => 'ID', + 'description' => __( 'Get the coupon by its global ID', 'wp-graphql-woocommerce' ), + ), + 'couponId' => array( + 'type' => 'Int', + 'description' => __( 'Get the coupon by its database ID', 'wp-graphql-woocommerce' ), + ), + 'code' => array( + 'type' => 'String', + 'description' => __( 'Get the coupon by its code', 'wp-graphql-woocommerce' ), + ), + ), + 'resolve' => function( $source, array $args, AppContext $context, ResolveInfo $info ) { + $coupon_id = null; if ( ! empty( $args['id'] ) ) { $id_components = Relay::fromGlobalId( $args['id'] ); if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); } + $coupon_id = absint( $id_components['id'] ); + $id = $args['id']; + $id_type = 'ID'; } elseif ( ! empty( $args['couponId'] ) ) { $coupon_id = absint( $args['couponId'] ); + $id = $args['couponId']; + $id_type = 'DATABASE_ID'; } elseif ( ! empty( $args['code'] ) ) { $coupon_id = \wc_get_coupon_id_by_code( $args['code'] ); + $id = $args['code']; + $id_type = 'CODE'; } - $coupon = Factory::resolve_crud_object( $coupon_id, $context ); - if ( get_post( $coupon_id )->post_type !== 'shop_coupon' ) { - /* translators: no coupon found error message */ - throw new UserError( sprintf( __( 'No coupon exists with this id: %1$s', 'wp-graphql-woocommerce' ), $args['id'] ) ); + if ( empty( $coupon_id ) ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No coupon ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); + } elseif ( get_post( $coupon_id )->post_type !== 'shop_coupon' ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No coupon exists with the %1$s: %2$s' ), $id_type, $id ) ); } - return $coupon; + return Factory::resolve_crud_object( $coupon_id, $context ); }, ) ); diff --git a/includes/type/object/class-order-type.php b/includes/type/object/class-order-type.php index 3504a4eda..8c42b6721 100644 --- a/includes/type/object/class-order-type.php +++ b/includes/type/object/class-order-type.php @@ -331,35 +331,70 @@ public static function register() { 'type' => 'ID', 'description' => __( 'Get the order by its global ID', 'wp-graphql-woocommerce' ), ), + 'idType' => array( + 'type' => 'OrderIdTypeEnum', + 'description' => __( 'Type of ID being used identify order', 'wp-graphql-woocommerce' ), + ), 'orderId' => array( - 'type' => 'Int', - 'description' => __( 'Get the order by its database ID', 'wp-graphql-woocommerce' ), + 'type' => 'Int', + 'description' => __( 'Get the order by its database ID', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "order(id: value, idType: value)" instead', + 'wp-graphql-woocommerce' + ), ), 'orderKey' => array( - 'type' => 'String', - 'description' => __( 'Get the order by its order number', 'wp-graphql-woocommerce' ), + 'type' => 'String', + 'description' => __( 'Get the order by its order number', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "order(id: value, idType: value)" instead', + 'wp-graphql-woocommerce' + ), ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $order_id = 0; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); - } - $order_id = absint( $id_components['id'] ); - } elseif ( ! empty( $args['orderId'] ) ) { - $order_id = absint( $args['orderId'] ); + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + /** + * Process deprecated arguments + * + * Will be removed in v0.5.x. + */ + if ( ! empty( $args['orderId'] ) ) { + $id = $args['orderId']; + $id_type = 'database_id'; } elseif ( ! empty( $args['orderKey'] ) ) { - $order_id = \wc_get_order_id_by_order_key( $args['orderKey'] ); + $id = $args['orderKey']; + $id_type = 'order_number'; + } + + $order_id = null; + switch ( $id_type ) { + case 'order_number': + $order_id = \wc_get_order_id_by_order_key( $id ); + break; + case 'database_id': + $order_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $order_id = absint( $id_components['id'] ); + break; } if ( empty( $order_id ) ) { /* translators: %1$s: ID type, %2$s: ID value */ - throw new UserError( sprintf( __( 'No order ID was found corresponding to the %1$s: %2$s' ), $id_type, $product_id ) ); + throw new UserError( sprintf( __( 'No order ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); } elseif ( get_post( $order_id )->post_type !== 'shop_order' ) { /* translators: %1$s: ID type, %2$s: ID value */ - throw new UserError( sprintf( __( 'No order exists with the %1$s: %2$s' ), $id_type, $product_id ) ); + throw new UserError( sprintf( __( 'No order exists with the %1$s: %2$s' ), $id_type, $id ) ); } // Check if user authorized to view order. diff --git a/includes/type/object/class-product-types.php b/includes/type/object/class-product-types.php index f1467ec76..bc684d35e 100644 --- a/includes/type/object/class-product-types.php +++ b/includes/type/object/class-product-types.php @@ -315,43 +315,104 @@ private static function register_product_query( $type ) { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'Get the product by its global ID', 'wp-graphql-woocommerce' ), + 'description' => __( 'ID to identify product with', 'wp-graphql-woocommerce' ), ), + 'idType' => array( + 'type' => 'ProductIdTypeEnum', + 'description' => __( 'Type of ID being used identify product', 'wp-graphql-woocommerce' ), + ), + /** + * DEPRECATED + * + * Will be removed in v0.5.x. + */ 'productId' => array( - 'type' => 'Int', - 'description' => __( 'Get the product by its database ID', 'wp-graphql-woocommerce' ), + 'type' => 'Int', + 'description' => __( 'Get the product by its database ID', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => sprintf( + /* translators: %s: product type */ + __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "%sProduct(id: value, idType: DATABASE_ID)" instead', + 'wp-graphql-woocommerce' + ), + $type + ), ), + /** + * DEPRECATED + * + * Will be removed in v0.5.x. + */ 'slug' => array( - 'type' => 'String', - 'description' => __( 'Get the product by its slug', 'wp-graphql-woocommerce' ), + 'type' => 'String', + 'description' => __( 'Get the product by its slug', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => sprintf( + /* translators: %s: product type */ + __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "%sProduct(id: value, idType: SLUG)" instead', + 'wp-graphql-woocommerce' + ), + $type + ), ), 'sku' => array( - 'type' => 'String', - 'description' => __( 'Get the product by its sku', 'wp-graphql-woocommerce' ), + 'type' => 'String', + 'description' => __( 'Get the product by its sku', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => sprintf( + /* translators: %s: product type */ + __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "%sProduct(id: value, idType: SKU)" instead', + 'wp-graphql-woocommerce' + ), + $type + ), ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) use ( $type ) { - $product_id = 0; - $id_type = ''; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); - } - $product_id = absint( $id_components['id'] ); - $id_type = 'ID'; - } elseif ( ! empty( $args['productId'] ) ) { - $product_id = absint( $args['productId'] ); - $id_type = 'product ID'; + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + /** + * Process deprecated arguments + * + * Will be removed in v0.5.x. + */ + if ( ! empty( $args['productId'] ) ) { + $id = $args['productId']; + $id_type = 'database_id'; } elseif ( ! empty( $args['slug'] ) ) { - $post = get_page_by_path( $args['slug'], OBJECT, 'product' ); - $product_id = ! empty( $post ) ? absint( $post->ID ) : 0; + $id = $args['slug']; $id_type = 'slug'; } elseif ( ! empty( $args['sku'] ) ) { - $product_id = \wc_get_product_id_by_sku( $args['sku'] ); + $id = $args['sku']; $id_type = 'sku'; } + $product_id = null; + switch ( $id_type ) { + case 'sku': + $product_id = \wc_get_product_id_by_sku( $id ); + break; + case 'slug': + $post = get_page_by_path( $id, OBJECT, 'product' ); + $product_id = ! empty( $post ) ? absint( $post->ID ) : 0; + break; + case 'database_id': + $product_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $product_id = absint( $id_components['id'] ); + break; + } + if ( empty( $product_id ) ) { /* translators: %1$s: ID type, %2$s: ID value */ throw new UserError( sprintf( __( 'No product ID was found corresponding to the %1$s: %2$s' ), $id_type, $product_id ) ); diff --git a/includes/type/object/class-product-variation-type.php b/includes/type/object/class-product-variation-type.php index a7b3a8f81..6db471f82 100644 --- a/includes/type/object/class-product-variation-type.php +++ b/includes/type/object/class-product-variation-type.php @@ -255,33 +255,58 @@ public static function register() { 'type' => 'ID', 'description' => __( 'Get the product variation by its global ID', 'wp-graphql-woocommerce' ), ), + 'idType' => array( + 'type' => 'ProductVariationIdTypeEnum', + 'description' => __( 'Type of ID being used identify product variation', 'wp-graphql-woocommerce' ), + ), 'variationId' => array( 'type' => 'Int', 'description' => __( 'Get the product variation by its database ID', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "productVariation(id: value, idType: DATABASE_ID)" instead', + 'wp-graphql-woocommerce' + ), ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $variation_id = 0; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); - } + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; - $arg = 'ID'; - $variation_id = absint( $id_components['id'] ); - } elseif ( ! empty( $args['variationId'] ) ) { - $arg = 'database ID'; - $variation_id = absint( $args['variationId'] ); + /** + * Process deprecated arguments + * + * Will be removed in v0.5.x. + */ + if ( ! empty( $args['variationId'] ) ) { + $id = $args['variationId']; + $id_type = 'database_id'; + } + + $variation_id = null; + switch ( $id_type ) { + case 'database_id': + $variation_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $variation_id = absint( $id_components['id'] ); + break; } - $variation = Factory::resolve_crud_object( $variation_id, $context ); - if ( get_post( $variation_id )->post_type !== 'product_variation' ) { - /* translators: no product variation found error message */ - throw new UserError( sprintf( __( 'No product variation exists with this %1$s: %2$s' ), $arg, $args['id'] ) ); + if ( empty( $variation_id ) ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No product variation ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); + } elseif ( get_post( $variation_id )->post_type !== 'product_variation' ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No product variation exists with the %1$s: %2$s' ), $id_type, $id ) ); } - return $variation; + return Factory::resolve_crud_object( $variation_id, $context ); }, ) ); diff --git a/includes/type/object/class-refund-type.php b/includes/type/object/class-refund-type.php index a9b42139d..b79ab2da9 100644 --- a/includes/type/object/class-refund-type.php +++ b/includes/type/object/class-refund-type.php @@ -70,58 +70,65 @@ public static function register() { 'type' => 'Refund', 'description' => __( 'A refund object', 'wp-graphql-woocommerce' ), 'args' => array( - 'id' => array( + 'id' => array( 'type' => array( 'non_null' => 'ID', ), ), + 'idType' => array( + 'type' => 'RefundIdTypeEnum', + 'description' => __( 'Type of ID being used identify refund', 'wp-graphql-woocommerce' ), + ), ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( ! isset( $id_components['id'] ) || ! absint( $id_components['id'] ) ) { - throw new UserError( __( 'The ID input is invalid', 'wp-graphql-woocommerce' ) ); + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + $refund_id = null; + switch ( $id_type ) { + case 'database_id': + $refund_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $refund_id = absint( $id_components['id'] ); + break; } - $refund_id = absint( $id_components['id'] ); - return Factory::resolve_crud_object( $refund_id, $context ); - }, - ) - ); - $post_by_args = array( - 'id' => array( - 'type' => 'ID', - 'description' => __( 'Get the refund by its global ID', 'wp-graphql-woocommerce' ), - ), - 'refundId' => array( - 'type' => 'Int', - 'description' => __( 'Get the refund by its database ID', 'wp-graphql-woocommerce' ), - ), - ); + if ( empty( $refund_id ) ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No refund ID was found corresponding to the %1$s: %2$s' ), $id_type, $id ) ); + } elseif ( get_post( $refund_id )->post_type !== 'shop_order_refund' ) { + /* translators: %1$s: ID type, %2$s: ID value */ + throw new UserError( sprintf( __( 'No refund exists with the %1$s: %2$s' ), $id_type, $id ) ); + } - register_graphql_field( - 'RootQuery', - 'refundBy', - array( - 'type' => 'Refund', - 'description' => __( 'A refund object', 'wp-graphql-woocommerce' ), - 'args' => $post_by_args, - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $refund_id = 0; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + // Check if user authorized to view order. + $post_type = get_post_type_object( 'shop_order_refund' ); + $is_authorized = current_user_can( $post_type->cap->edit_others_posts ); + if ( get_current_user_id() ) { + $refund = \wc_get_order( $refund_id ); + $order_id = $refund->get_parent_id(); + $orders = wc_get_orders( + array( + 'type' => 'shop_order', + 'post__in' => array( $order_id ), + 'customer_id' => get_current_user_id(), + 'no_rows_found' => true, + 'return' => 'ids', + ) + ); + + if ( in_array( $order_id, $orders, true ) ) { + $is_authorized = true; } - $refund_id = absint( $id_components['id'] ); - } elseif ( ! empty( $args['refundId'] ) ) { - $refund_id = absint( $args['refundId'] ); } - $refund = Factory::resolve_crud_object( $refund_id, $context ); - if ( get_post( $refund_id )->post_type !== 'shop_order_refund' ) { - /* translators: not refund found error message */ - throw new UserError( sprintf( __( 'No refund exists with this id: %1$s' ), $refund_id ) ); - } + $refund = $is_authorized ? Factory::resolve_crud_object( $refund_id, $context ) : null; return $refund; }, diff --git a/tests/wpunit/CouponQueriesTest.php b/tests/wpunit/CouponQueriesTest.php index 528ec1c37..f69ab6a7d 100644 --- a/tests/wpunit/CouponQueriesTest.php +++ b/tests/wpunit/CouponQueriesTest.php @@ -99,13 +99,13 @@ public function testCouponQuery() { $this->assertEquals( $expected, $actual ); } - public function testCouponByQueryAndArgs() { + public function testCouponQueryAndIds() { wp_set_current_user( $this->customer ); $id = Relay::toGlobalId( 'shop_coupon', $this->coupon ); $coupon = new WC_Coupon( $this->coupon ); $query = ' - query ($id: ID, $couponId: Int, $code: String) { - couponBy(id: $id, couponId: $couponId, code: $code) { + query ($id: ID!, $idType: CouponIdTypeEnum) { + coupon(id: $id, idType: $idType) { id } } @@ -114,11 +114,19 @@ public function testCouponByQueryAndArgs() { /** * Assertion One * - * Testing "id" query argument + * Testing "ID" ID type. */ - $variables = array( 'id' => $id ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'couponBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); + $expected = array( 'data' => array( 'coupon' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -128,11 +136,19 @@ public function testCouponByQueryAndArgs() { /** * Assertion Two * - * Testing "couponId" query argument + * Testing "DATABASE_ID" ID type */ - $variables = array( 'couponId' => $coupon->get_id() ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'couponBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => $coupon->get_id(), + 'idType' => 'DATABASE_ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); + $expected = array( 'data' => array( 'coupon' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -142,11 +158,19 @@ public function testCouponByQueryAndArgs() { /** * Assertion Three * - * Testing "couponId" query argument + * Testing "CODE" ID type. */ - $variables = array( 'code' => $coupon->get_code() ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'couponBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => $coupon->get_code(), + 'idType' => 'CODE', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); + $expected = array( 'data' => array( 'coupon' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); diff --git a/tests/wpunit/MetaDataQueriesTest.php b/tests/wpunit/MetaDataQueriesTest.php index ae03b305b..693fcd197 100644 --- a/tests/wpunit/MetaDataQueriesTest.php +++ b/tests/wpunit/MetaDataQueriesTest.php @@ -62,7 +62,7 @@ private function createObjects() { $this->customer_id = $this->customers->create( $data ); // Create Order and Refund with meta data. - $this->order_id = $this->orders->create( $data ); + $this->order_id = $this->orders->create( array_merge( $data, array( 'customer_id' => $this->customer ) ) ); $this->order_items->add_fee( $this->order_id, $data ); $this->refund_id = $this->refunds->create( $this->order_id, $data ); @@ -631,6 +631,7 @@ public function testRefundMetaDataQueries() { /** * Assertion One */ + wp_set_current_user( $this->customer ); $variables = array( 'id' => $id ); $actual = graphql( array( diff --git a/tests/wpunit/OrderQueriesTest.php b/tests/wpunit/OrderQueriesTest.php index e0269b6e0..9b22f3439 100644 --- a/tests/wpunit/OrderQueriesTest.php +++ b/tests/wpunit/OrderQueriesTest.php @@ -153,12 +153,12 @@ public function testOrderQuery() { $this->assertEquals( $expected, $actual ); } - public function testOrderQueryAndArgs() { + public function testOrderQueryAndIds() { $id = Relay::toGlobalId( 'shop_order', $this->order ); $query = ' - query ($id: ID, $orderId: Int, $orderKey: String) { - order(id: $id, orderId: $orderId, orderKey: $orderKey) { + query ($id: ID!, $idType: OrderIdTypeEnum ) { + order(id: $id, idType: $idType) { id } } @@ -170,10 +170,18 @@ public function testOrderQueryAndArgs() { /** * Assertion One * - * tests query and "id" arg + * tests "ID" ID type. */ - $variables = array( 'id' => $id ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); $expected = array( 'data' => array( 'order' => array( 'id' => $id ) ) ); // use --debug flag to view. @@ -184,10 +192,18 @@ public function testOrderQueryAndArgs() { /** * Assertion Two * - * tests query and "orderId" arg + * tests "DATABASE_ID" ID type. */ - $variables = array( 'orderId' => $this->order ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); + $variables = array( + 'id' => $this->order, + 'idType' => 'DATABASE_ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); $expected = array( 'data' => array( 'order' => array( 'id' => $id ) ) ); // use --debug flag to view. @@ -198,10 +214,18 @@ public function testOrderQueryAndArgs() { /** * Assertion Three * - * tests query and "orderNumber" arg + * tests "ORDER_NUMBER" ID type */ - $variables = array( 'orderKey' => $this->order_helper->get_order_key( $this->order ) ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); + $variables = array( + 'id' => $this->order_helper->get_order_key( $this->order ), + 'idType' => 'ORDER_NUMBER', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); $expected = array( 'data' => array( 'order' => array( 'id' => $id ) ) ); // use --debug flag to view. diff --git a/tests/wpunit/ProductQueriesTest.php b/tests/wpunit/ProductQueriesTest.php index eadc910cc..a9e19def8 100644 --- a/tests/wpunit/ProductQueriesTest.php +++ b/tests/wpunit/ProductQueriesTest.php @@ -250,11 +250,11 @@ public function testProductTaxonomies() { $this->assertEquals( $expected, $actual ); } - public function testProductByQueryAndArgs() { + public function testProductQueryAndIds() { $id = $this->helper->to_relay_id( $this->product ); $query = ' - query ( $id: ID, $productId: Int, $slug: String, $sku: String ) { - productBy( id: $id, productId: $productId, slug: $slug, sku: $sku ) { + query ( $id: ID!, $idType: ProductIdTypeEnum ) { + product( id: $id, idType: $idType ) { ... on SimpleProduct { id } @@ -267,9 +267,17 @@ public function testProductByQueryAndArgs() { * * Test querying product with "productId" argument. */ - $variables = array( 'productId' => $this->product ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'productBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => $this->product, + 'idType' => 'DATABASE_ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); + $expected = array( 'data' => array( 'product' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -281,9 +289,17 @@ public function testProductByQueryAndArgs() { * * Test querying product with "id" argument. */ - $variables = array( 'id' => $id ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'productBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); + $expected = array( 'data' => array( 'product' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -295,9 +311,17 @@ public function testProductByQueryAndArgs() { * * Test querying product with "slug" argument. */ - $variables = array( 'slug' => 'product-slug' ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'productBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => 'product-slug', + 'idType' => 'SLUG', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); + $expected = array( 'data' => array( 'product' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -309,9 +333,17 @@ public function testProductByQueryAndArgs() { * * Test querying product with "sku" argument. */ - $variables = array( 'sku' => 'product-sku' ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); - $expected = array( 'data' => array( 'productBy' => array( 'id' => $id ) ) ); + $variables = array( + 'id' => 'product-sku', + 'idType' => 'SKU', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables + ) + ); + $expected = array( 'data' => array( 'product' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); diff --git a/tests/wpunit/ProductVariationQueriesTest.php b/tests/wpunit/ProductVariationQueriesTest.php index 51aa0f7c4..8bef25c54 100644 --- a/tests/wpunit/ProductVariationQueriesTest.php +++ b/tests/wpunit/ProductVariationQueriesTest.php @@ -29,8 +29,8 @@ public function testVariationQuery() { $variation_id = $this->products['variations'][0]; $id = $this->helper->to_relay_id( $variation_id ); $query = ' - query ($id: ID, $variationId: Int) { - productVariation(id: $id, variationId: $variationId) { + query ($id: ID, $idType: ProductVariationIdTypeEnum) { + productVariation(id: $id, idType: $idType) { id variationId name @@ -77,10 +77,18 @@ public function testVariationQuery() { /** * Assertion One * - * test query and "id" query argument + * test "ID" ID type. */ - $variables = array( 'id' => $id ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); $expected = array( 'data' => array( 'productVariation' => $this->helper->print_query( $variation_id ) ) ); // use --debug flag to view. @@ -93,10 +101,19 @@ public function testVariationQuery() { /** * Assertion Two * - * test query and "methodId" query argument + * test "DATABASE_ID" ID type. */ - $variables = array( 'variationId' => $variation_id ); - $actual = graphql( array( 'query' => $query, 'variables' => $variables ) ); + $variables = array( + 'id' => $variation_id, + 'idType' => 'DATABASE_ID', + + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); $expected = array( 'data' => array( 'productVariation' => $this->helper->print_query( $variation_id ) ) ); // use --debug flag to view. diff --git a/tests/wpunit/RefundQueriesTest.php b/tests/wpunit/RefundQueriesTest.php index 634d16db3..cc575f7dc 100644 --- a/tests/wpunit/RefundQueriesTest.php +++ b/tests/wpunit/RefundQueriesTest.php @@ -17,7 +17,9 @@ public function setUp() { $this->order_helper = $this->getModule('\Helper\Wpunit')->order(); $this->refund_helper = $this->getModule('\Helper\Wpunit')->refund(); $this->customer_helper = $this->getModule('\Helper\Wpunit')->refund(); - $this->order = $this->order_helper->create(); + $this->order = $this->order_helper->create( + array( 'customer_id' => $this->customer ) + ); $this->refund = $this->refund_helper->create( $this->order ); } @@ -98,12 +100,12 @@ public function testRefundQuery() { $this->assertEquals( $expected, $actual ); } - public function testRefundByQueryAndArgs() { + public function testRefundQueryAndIds() { $id = Relay::toGlobalId( 'shop_order_refund', $this->refund ); $query = ' - query ( $id: ID, $refundId: Int ) { - refundBy( id: $id, refundId: $refundId ) { + query ( $id: ID!, $idType: RefundIdTypeEnum ) { + refund( id: $id, idType: $idType ) { id } } @@ -114,14 +116,18 @@ public function testRefundByQueryAndArgs() { * * Test query and "id" argument */ - $variables = array( 'id' => $id ); + wp_set_current_user( $this->customer ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); $actual = graphql( array( 'query' => $query, 'variables' => $variables, ) ); - $expected = array( 'data' => array( 'refundBy' => array( 'id' => $id ) ) ); + $expected = array( 'data' => array( 'refund' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -133,14 +139,17 @@ public function testRefundByQueryAndArgs() { * * Test query and "refundId" argument */ - $variables = array( 'refundId' => $this->refund ); + $variables = array( + 'id' => $this->refund, + 'idType' => 'DATABASE_ID', + ); $actual = graphql( array( 'query' => $query, 'variables' => $variables, ) ); - $expected = array( 'data' => array( 'refundBy' => array( 'id' => $id ) ) ); + $expected = array( 'data' => array( 'refund' => array( 'id' => $id ) ) ); // use --debug flag to view. codecept_debug( $actual ); @@ -325,6 +334,7 @@ public function testOrderToRefundsConnection() { public function testCustomerToRefundsConnection() { $order = $this->order_helper->create( array( 'customer_id' => $this->customer ) ); $refunds = array( + $this->refund, $this->refund_helper->create( $order, array( 'amount' => 0.5 ) ), $this->refund_helper->create( $order, array( 'status' => 'pending', 'amount' => 0.5 ) ), ); diff --git a/vendor/autoload.php b/vendor/autoload.php index 31710106c..156abf9cd 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit4127ab9804a522d85e48188e585a812c::getLoader(); +return ComposerAutoloaderInitcab7a6a7239ac8af7f5a764eb6b56ee1::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 08ec3aec2..6730abb9a 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -85,6 +85,7 @@ 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Countries' => $baseDir . '/includes/type/enum/class-countries.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Customer_Connection_Orderby_Enum' => $baseDir . '/includes/type/enum/class-customer-connection-orderby-enum.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Discount_Type' => $baseDir . '/includes/type/enum/class-discount-type.php', + 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Id_Type_Enums' => $baseDir . '/includes/type/enum/class-id-type-enums.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Manage_Stock' => $baseDir . '/includes/type/enum/class-manage-stock.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Order_Status' => $baseDir . '/includes/type/enum/class-order-status.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Orders_Orderby_Enum' => $baseDir . '/includes/type/enum/class-orders-orderby-enum.php', diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 375bfad9b..677e21cc7 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit4127ab9804a522d85e48188e585a812c +class ComposerAutoloaderInitcab7a6a7239ac8af7f5a764eb6b56ee1 { private static $loader; @@ -19,15 +19,15 @@ public static function getLoader() return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit4127ab9804a522d85e48188e585a812c', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitcab7a6a7239ac8af7f5a764eb6b56ee1', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit4127ab9804a522d85e48188e585a812c', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitcab7a6a7239ac8af7f5a764eb6b56ee1', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit4127ab9804a522d85e48188e585a812c::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -48,19 +48,19 @@ public static function getLoader() $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit4127ab9804a522d85e48188e585a812c::$files; + $includeFiles = Composer\Autoload\ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire4127ab9804a522d85e48188e585a812c($fileIdentifier, $file); + composerRequirecab7a6a7239ac8af7f5a764eb6b56ee1($fileIdentifier, $file); } return $loader; } } -function composerRequire4127ab9804a522d85e48188e585a812c($fileIdentifier, $file) +function composerRequirecab7a6a7239ac8af7f5a764eb6b56ee1($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index ded3b99e7..96c787a5e 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit4127ab9804a522d85e48188e585a812c +class ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1 { public static $files = array ( '914b07b8cf678ed0b81bfdb5d23b4f2b' => __DIR__ . '/../..' . '/includes/connection/common-post-type-args.php', @@ -113,6 +113,7 @@ class ComposerStaticInit4127ab9804a522d85e48188e585a812c 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Countries' => __DIR__ . '/../..' . '/includes/type/enum/class-countries.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Customer_Connection_Orderby_Enum' => __DIR__ . '/../..' . '/includes/type/enum/class-customer-connection-orderby-enum.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Discount_Type' => __DIR__ . '/../..' . '/includes/type/enum/class-discount-type.php', + 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Id_Type_Enums' => __DIR__ . '/../..' . '/includes/type/enum/class-id-type-enums.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Manage_Stock' => __DIR__ . '/../..' . '/includes/type/enum/class-manage-stock.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Order_Status' => __DIR__ . '/../..' . '/includes/type/enum/class-order-status.php', 'WPGraphQL\\WooCommerce\\Type\\WPEnum\\Orders_Orderby_Enum' => __DIR__ . '/../..' . '/includes/type/enum/class-orders-orderby-enum.php', @@ -170,9 +171,9 @@ class ComposerStaticInit4127ab9804a522d85e48188e585a812c public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit4127ab9804a522d85e48188e585a812c::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit4127ab9804a522d85e48188e585a812c::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit4127ab9804a522d85e48188e585a812c::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitcab7a6a7239ac8af7f5a764eb6b56ee1::$classMap; }, null, ClassLoader::class); } diff --git a/wp-graphql-woocommerce.php b/wp-graphql-woocommerce.php index b1ea4dc1e..f985ea421 100644 --- a/wp-graphql-woocommerce.php +++ b/wp-graphql-woocommerce.php @@ -3,7 +3,7 @@ * Plugin Name: WPGraphQL WooCommerce (WooGraphQL) * Plugin URI: https://github.com/kidunot89/wp-graphql-woocommerce * Description: Adds Woocommerce Functionality to WPGraphQL schema. - * Version: 0.4.0 + * Version: 0.4.1 * Author: kidunot89 * Author URI: https://axistaylor.com * Text Domain: wp-graphql-woocommerce @@ -13,7 +13,7 @@ * WC requires at least: 3.0.0 * WC tested up to: 3.7.1 * WPGraphQL requires at least: 0.6.0+ - * WPGraphQL-JWT-Authentication requires at least: 0.4.0+ + * WPGraphQL-JWT-Authentication requires at least: 0.3.4+ * * @package WPGraphQL\WooCommerce * @author kidunot89 From 8afc1e90cad68657d17b7bf68410c84e59308931 Mon Sep 17 00:00:00 2001 From: Geoff Taylor Date: Sat, 25 Jan 2020 12:36:47 -0500 Subject: [PATCH 2/2] More queries updated. --- includes/mutation/class-checkout.php | 2 +- includes/type/enum/class-id-type-enums.php | 21 ++++++-- .../interface/class-product-attribute.php | 2 +- includes/type/interface/class-product.php | 3 +- includes/type/object/class-order-type.php | 2 +- includes/type/object/class-product-types.php | 6 ++- .../object/class-product-variation-type.php | 6 +-- includes/type/object/class-refund-type.php | 5 +- .../object/class-shipping-method-type.php | 51 ++++++++++++++----- includes/type/object/class-tax-rate-type.php | 51 ++++++++++++++----- tests/wpunit/ShippingMethodQueriesTest.php | 32 +++++++++--- 11 files changed, 129 insertions(+), 52 deletions(-) diff --git a/includes/mutation/class-checkout.php b/includes/mutation/class-checkout.php index 0c38de48a..7e161213d 100644 --- a/includes/mutation/class-checkout.php +++ b/includes/mutation/class-checkout.php @@ -97,7 +97,7 @@ public static function get_output_fields() { return is_user_logged_in() ? new Customer( get_current_user_id() ) : null; }, ), - 'result' => array( + 'result' => array( 'type' => 'String', 'resolve' => function( $payload ) { return $payload['result']; diff --git a/includes/type/enum/class-id-type-enums.php b/includes/type/enum/class-id-type-enums.php index 151a79e1c..778e5e3db 100644 --- a/includes/type/enum/class-id-type-enums.php +++ b/includes/type/enum/class-id-type-enums.php @@ -23,7 +23,7 @@ public static function register() { register_graphql_enum_type( 'CouponIdTypeEnum', array( - 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'description' => __( 'The Type of Identifier used to fetch a single Coupon. Default is ID.', 'wp-graphql' ), 'values' => array( 'id' => self::get_value( 'id' ), 'database_id' => self::get_value( 'database_id' ), @@ -39,7 +39,7 @@ public static function register() { register_graphql_enum_type( 'OrderIdTypeEnum', array( - 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'description' => __( 'The Type of Identifier used to fetch a single Order. Default is ID.', 'wp-graphql' ), 'values' => array( 'id' => self::get_value( 'id' ), 'database_id' => self::get_value( 'database_id' ), @@ -55,7 +55,7 @@ public static function register() { register_graphql_enum_type( 'ProductIdTypeEnum', array( - 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'description' => __( 'The Type of Identifier used to fetch a single Product. Default is ID.', 'wp-graphql' ), 'values' => array( 'id' => self::get_value( 'id' ), 'database_id' => self::get_value( 'database_id' ), @@ -72,7 +72,7 @@ public static function register() { register_graphql_enum_type( 'ProductVariationIdTypeEnum', array( - 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'description' => __( 'The Type of Identifier used to fetch a single ProductVariation. Default is ID.', 'wp-graphql' ), 'values' => array( 'id' => self::get_value( 'id' ), 'database_id' => self::get_value( 'database_id' ), @@ -83,7 +83,18 @@ public static function register() { register_graphql_enum_type( 'RefundIdTypeEnum', array( - 'description' => __( 'The Type of Identifier used to fetch a single resource. Default is ID.', 'wp-graphql' ), + 'description' => __( 'The Type of Identifier used to fetch a single Refund. Default is ID.', 'wp-graphql' ), + 'values' => array( + 'id' => self::get_value( 'id' ), + 'database_id' => self::get_value( 'database_id' ), + ), + ) + ); + + register_graphql_enum_type( + 'ShippingMethodIdTypeEnum', + array( + 'description' => __( 'The Type of Identifier used to fetch a single Shipping Method. Default is ID.', 'wp-graphql' ), 'values' => array( 'id' => self::get_value( 'id' ), 'database_id' => self::get_value( 'database_id' ), diff --git a/includes/type/interface/class-product-attribute.php b/includes/type/interface/class-product-attribute.php index d1cf0e307..7e9c35a98 100644 --- a/includes/type/interface/class-product-attribute.php +++ b/includes/type/interface/class-product-attribute.php @@ -60,7 +60,7 @@ public static function get_fields() { return ! empty( $attribute->get_name() ) ? $attribute->get_name() : null; }, ), - 'options' => array( + 'options' => array( 'type' => array( 'list_of' => 'String' ), 'description' => __( 'Attribute options', 'wp-graphql-woocommerce' ), 'resolve' => function ( $attribute ) { diff --git a/includes/type/interface/class-product.php b/includes/type/interface/class-product.php index 8c3205964..07b59431c 100644 --- a/includes/type/interface/class-product.php +++ b/includes/type/interface/class-product.php @@ -56,7 +56,8 @@ public static function register_interface( &$type_registry ) { 'description' => __( 'A product object', 'wp-graphql-woocommerce' ), 'args' => array( 'id' => array( - 'type' => array( 'non_null' => 'ID' ), + 'type' => array( 'non_null' => 'ID' ), + 'description' => __( 'The ID for identifying the product', 'wp-graphql-woocommerce' ), ), 'idType' => array( 'type' => 'ProductIdTypeEnum', diff --git a/includes/type/object/class-order-type.php b/includes/type/object/class-order-type.php index 8c42b6721..7e04f501b 100644 --- a/includes/type/object/class-order-type.php +++ b/includes/type/object/class-order-type.php @@ -329,7 +329,7 @@ public static function register() { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'Get the order by its global ID', 'wp-graphql-woocommerce' ), + 'description' => __( 'The ID for identifying the order', 'wp-graphql-woocommerce' ), ), 'idType' => array( 'type' => 'OrderIdTypeEnum', diff --git a/includes/type/object/class-product-types.php b/includes/type/object/class-product-types.php index bc684d35e..babee0cd5 100644 --- a/includes/type/object/class-product-types.php +++ b/includes/type/object/class-product-types.php @@ -315,7 +315,11 @@ private static function register_product_query( $type ) { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'ID to identify product with', 'wp-graphql-woocommerce' ), + 'description' => sprintf( + /* translators: %s: product type */ + __( 'The ID for identifying the %s product', 'wp-graphql-woocommerce' ), + $type + ), ), 'idType' => array( 'type' => 'ProductIdTypeEnum', diff --git a/includes/type/object/class-product-variation-type.php b/includes/type/object/class-product-variation-type.php index 6db471f82..2721ebf88 100644 --- a/includes/type/object/class-product-variation-type.php +++ b/includes/type/object/class-product-variation-type.php @@ -253,15 +253,15 @@ public static function register() { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'Get the product variation by its global ID', 'wp-graphql-woocommerce' ), + 'description' => __( 'The ID for identifying the product variation', 'wp-graphql-woocommerce' ), ), 'idType' => array( 'type' => 'ProductVariationIdTypeEnum', 'description' => __( 'Type of ID being used identify product variation', 'wp-graphql-woocommerce' ), ), 'variationId' => array( - 'type' => 'Int', - 'description' => __( 'Get the product variation by its database ID', 'wp-graphql-woocommerce' ), + 'type' => 'Int', + 'description' => __( 'Get the product variation by its database ID', 'wp-graphql-woocommerce' ), 'isDeprecated' => true, 'deprecationReason' => __( 'This argument has been deprecation, and will be removed in v0.5.x. Please use "productVariation(id: value, idType: DATABASE_ID)" instead', diff --git a/includes/type/object/class-refund-type.php b/includes/type/object/class-refund-type.php index b79ab2da9..6422647b6 100644 --- a/includes/type/object/class-refund-type.php +++ b/includes/type/object/class-refund-type.php @@ -71,9 +71,8 @@ public static function register() { 'description' => __( 'A refund object', 'wp-graphql-woocommerce' ), 'args' => array( 'id' => array( - 'type' => array( - 'non_null' => 'ID', - ), + 'type' => array( 'non_null' => 'ID' ), + 'description' => __( 'The ID for identifying the refund', 'wp-graphql-woocommerce' ), ), 'idType' => array( 'type' => 'RefundIdTypeEnum', diff --git a/includes/type/object/class-shipping-method-type.php b/includes/type/object/class-shipping-method-type.php index 7a4842ca2..525821fa0 100644 --- a/includes/type/object/class-shipping-method-type.php +++ b/includes/type/object/class-shipping-method-type.php @@ -61,26 +61,49 @@ public static function register() { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'Get the shipping method by its global ID', 'wp-graphql-woocommerce' ), + 'description' => __( 'The ID for identifying the shipping method', 'wp-graphql-woocommerce' ), + ), + 'idType' => array( + 'type' => 'ShippingMethodIdTypeEnum', + 'description' => __( 'Type of ID being used identify product variation', 'wp-graphql-woocommerce' ), ), 'methodId' => array( - 'type' => 'ID', - 'description' => __( 'Get the shipping method by its database ID', 'wp-graphql-woocommerce' ), + 'type' => 'ID', + 'description' => __( 'Get the shipping method by its database ID', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "shippingMethod(id: value, idType: DATABASE_ID)" instead.', + 'wp-graphql-woocommerce' + ), ), ), 'resolve' => function ( $source, array $args ) { - $method_id = 0; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); - } + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + /** + * Process deprecated arguments + * + * Will be removed in v0.5.x. + */ + if ( ! empty( $args['methodId'] ) ) { + $id = $args['methodId']; + $id_type = 'database_id'; + } - $arg = 'ID'; - $method_id = $id_components['id']; - } elseif ( ! empty( $args['methodId'] ) ) { - $arg = 'database ID'; - $method_id = $args['methodId']; + $method_id = null; + switch ( $id_type ) { + case 'database_id': + $method_id = $id; + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $method_id = $id_components['id']; + break; } return Factory::resolve_shipping_method( $method_id ); diff --git a/includes/type/object/class-tax-rate-type.php b/includes/type/object/class-tax-rate-type.php index ec42e044e..9f07eaeb6 100644 --- a/includes/type/object/class-tax-rate-type.php +++ b/includes/type/object/class-tax-rate-type.php @@ -97,26 +97,49 @@ public static function register() { 'args' => array( 'id' => array( 'type' => 'ID', - 'description' => __( 'Get the tax rate by its global ID', 'wp-graphql-woocommerce' ), + 'description' => __( 'The ID for identifying the tax rate', 'wp-graphql-woocommerce' ), + ), + 'idType' => array( + 'type' => 'TaxRateIdTypeEnum', + 'description' => __( 'Type of ID being used identify tax rate', 'wp-graphql-woocommerce' ), ), 'rateId' => array( - 'type' => 'Int', - 'description' => __( 'Get the tax rate by its database ID', 'wp-graphql-woocommerce' ), + 'type' => 'Int', + 'description' => __( 'Get the tax rate by its database ID', 'wp-graphql-woocommerce' ), + 'isDeprecated' => true, + 'deprecationReason' => __( + 'This argument has been deprecation, and will be removed in v0.5.x. Please use "taxRate(id: value, idType: DATABASE_ID)" instead.', + 'wp-graphql-woocommerce' + ), ), ), 'resolve' => function ( $source, array $args ) { - $rate_id = 0; - if ( ! empty( $args['id'] ) ) { - $id_components = Relay::fromGlobalId( $args['id'] ); - if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { - throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); - } + $id = isset( $args['id'] ) ? $args['id'] : null; + $id_type = isset( $args['idType'] ) ? $args['idType'] : 'global_id'; + + /** + * Process deprecated arguments + * + * Will be removed in v0.5.x. + */ + if ( ! empty( $args['rateId'] ) ) { + $id = $args['rateId']; + $id_type = 'database_id'; + } - $arg = 'ID'; - $rate_id = absint( $id_components['id'] ); - } elseif ( ! empty( $args['rateId'] ) ) { - $arg = 'database ID'; - $rate_id = absint( $args['rateId'] ); + $rate_id = null; + switch ( $id_type ) { + case 'database_id': + $rate_id = absint( $id ); + break; + case 'global_id': + default: + $id_components = Relay::fromGlobalId( $id ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" is invalid', 'wp-graphql-woocommerce' ) ); + } + $rate_id = absint( $id_components['id'] ); + break; } return Factory::resolve_tax_rate( $rate_id ); diff --git a/tests/wpunit/ShippingMethodQueriesTest.php b/tests/wpunit/ShippingMethodQueriesTest.php index c55c30924..d3eabcb1d 100644 --- a/tests/wpunit/ShippingMethodQueriesTest.php +++ b/tests/wpunit/ShippingMethodQueriesTest.php @@ -28,8 +28,8 @@ public function testShippingMethodQueryAndArgs() { $id = Relay::toGlobalId( 'shipping_method', $this->method ); $query = ' - query shippingMethodQuery( $id: ID, $methodId: ID ) { - shippingMethod( id: $id, methodId: $methodId ) { + query( $id: ID!, $idType: ShippingMethodIdTypeEnum ) { + shippingMethod( id: $id, idType: $idType ) { id methodId title @@ -41,10 +41,18 @@ public function testShippingMethodQueryAndArgs() { /** * Assertion One * - * test query and "id" query argument + * test "ID" ID type. */ - $variables = array( 'id' => $id ); - $actual = do_graphql_request( $query, 'shippingMethodQuery', $variables ); + $variables = array( + 'id' => $id, + 'idType' => 'ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); $expected = array( 'data' => array( 'shippingMethod' => $this->helper->print_query( $this->method ) ) ); // use --debug flag to view. @@ -55,10 +63,18 @@ public function testShippingMethodQueryAndArgs() { /** * Assertion Two * - * test query and "methodId" query argument + * test "DATABASE_ID" ID type. */ - $variables = array( 'methodId' => $this->method ); - $actual = do_graphql_request( $query, 'shippingMethodQuery', $variables ); + $variables = array( + 'id' => $this->method, + 'idType' => 'DATABASE_ID', + ); + $actual = graphql( + array( + 'query' => $query, + 'variables' => $variables, + ) + ); $expected = array( 'data' => array( 'shippingMethod' => $this->helper->print_query( $this->method ) ) ); // use --debug flag to view.