• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wp-graphql / wp-graphql-woocommerce / 9122745284

17 May 2024 04:03AM UTC coverage: 85.048% (+0.4%) from 84.647%
9122745284

push

github

web-flow
feat: Queries and mutations for shipping zones, tax classes, and tax rates. (#856)

* fix: General bugfixes and improvements

* devops: New mutations and types tested and compliance with Linter and PHPStan

* chore: hooks added to the mutation resolvers

* feat: permission checks added

* chore: Linter and compliance met

* chore: Linter and compliance met

1252 of 1399 new or added lines in 39 files covered. (89.49%)

9 existing lines in 2 files now uncovered.

12423 of 14607 relevant lines covered (85.05%)

70.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.91
/includes/data/loader/class-wc-db-loader.php
1
<?php
2
/**
3
 * DataLoader - WC_Db_Loader
4
 *
5
 * Loads Models for WooCommerce objects defined in custom DB tables.
6
 *
7
 * @package WPGraphQL\WooCommerce\Data\Loader
8
 * @since 0.5.0
9
 */
10

11
namespace WPGraphQL\WooCommerce\Data\Loader;
12

13
use GraphQL\Error\UserError;
14
use WPGraphQL\Data\Loader\AbstractDataLoader;
15
use WPGraphQL\WooCommerce\Data\Factory;
16
use WPGraphQL\WooCommerce\Model\Shipping_Method;
17
use WPGraphQL\WooCommerce\Model\Shipping_Zone;
18
use WPGraphQL\WooCommerce\Model\Tax_Rate;
19

20
/**
21
 * Class WC_Db_Loader
22
 */
23
class WC_Db_Loader extends AbstractDataLoader {
24
        /**
25
         * Stores loaded CPTs.
26
         *
27
         * @var array
28
         */
29
        protected $loaded_objects;
30

31
        /**
32
         * Loader type
33
         *
34
         * @var string
35
         */
36
        protected $loader_type;
37

38
        /**
39
         * WC_Db_Loader constructor
40
         *
41
         * @param \WPGraphQL\AppContext $context      AppContext instance.
42
         * @param string                $loader_type  Type of loader be initialized.
43
         */
44
        public function __construct( $context, $loader_type ) {
45
                $this->loader_type = $loader_type;
153✔
46

47
                parent::__construct( $context );
153✔
48
        }
49

50
        /**
51
         * Given array of keys, loads and returns a map consisting of keys from `keys` array and loaded
52
         * posts as the values
53
         *
54
         * @param array $keys - array of IDs.
55
         *
56
         * @return array
57
         * @throws \Exception Invalid loader type.
58
         */
59
        public function loadKeys( array $keys ) {
60
                $loader = null;
24✔
61
                switch ( $this->loader_type ) {
24✔
62
                        case 'CART_ITEM':
24✔
63
                                $loader = [ $this, 'load_cart_item_from_key' ];
×
64
                                break;
×
65
                        case 'DOWNLOADABLE_ITEM':
24✔
66
                                $loader = [ $this, 'load_downloadable_item_from_id' ];
×
67
                                break;
×
68
                        case 'TAX_CLASS':
24✔
NEW
69
                                $loader = [ $this, 'load_tax_class_from_slug' ];
×
NEW
70
                                break;
×
71
                        case 'TAX_RATE':
24✔
72
                                $loader = [ $this, 'load_tax_rate_from_id' ];
14✔
73
                                break;
14✔
74
                        case 'ORDER_ITEM':
10✔
75
                                $loader = [ $this, 'load_order_item_from_id' ];
×
76
                                break;
×
77
                        case 'SHIPPING_METHOD':
10✔
UNCOV
78
                                $loader = [ $this, 'load_shipping_method_from_id' ];
×
UNCOV
79
                                break;
×
80
                        case 'SHIPPING_ZONE':
10✔
81
                                $loader = [ $this, 'load_shipping_zone_from_id' ];
10✔
82
                                break;
10✔
83
                        default:
84
                                /**
85
                                 * For adding custom key types to this loader
86
                                 *
87
                                 * @param callable|null $loader       Callback that gets entry from key.
88
                                 * @param string        $loader_type  Used to determine loader being used for this instance of the loader.
89
                                 */
90
                                $loader = apply_filters( 'woographql_db_loader_func', null, $this->loader_type );
×
91

92
                                if ( empty( $loader ) ) {
×
93
                                        throw new \Exception(
×
94
                                                /* translators: %s: Loader Type */
95
                                                sprintf( __( 'Loader type invalid: %s', 'wp-graphql-woocommerce' ), $this->loader_type )
×
96
                                        );
×
97
                                }
98
                }//end switch
99

100
                $loaded_items = [];
24✔
101

102
                /**
103
                 * Loop over the keys and return an array of items.
104
                 */
105
                foreach ( $keys as $key ) {
24✔
106
                        $loaded_items[ $key ] = call_user_func( $loader, $key );
24✔
107
                }
108

109
                return ! empty( $loaded_items ) ? $loaded_items : [];
24✔
110
        }
111

112
        /**
113
         * Returns the cart item connected the provided key.
114
         *
115
         * @param string $key - Cart item key.
116
         *
117
         * @return array
118
         */
119
        public function load_cart_item_from_key( $key ) {
120
                // Add the cart item's product and product variation to WC-CPT buffer.
121
                return Factory::resolve_cart()->get_cart_item( $key );
×
122
        }
123

124
        /**
125
         * Returns the downloadable item connected the provided IDs.
126
         *
127
         * @param int $id - Downloadable item ID.
128
         *
129
         * @return \WC_Customer_Download|null
130
         */
131
        public function load_downloadable_item_from_id( $id ) {
132
                $node = new \WC_Customer_Download( $id );
×
133
                return 0 === $node->get_id() ? $node : null;
×
134
        }
135

136
        /**
137
         * Returns the tax class connected the provided IDs.
138
         *
139
         * @param int $slug - Tax class slug.
140
         *
141
         * @return array|null
142
         */
143
        public function load_tax_class_from_slug( $slug ) {
NEW
144
                if ( 'standard' === $slug ) {
×
NEW
145
                        return [
×
NEW
146
                                'slug' => 'standard',
×
NEW
147
                                'name' => __( 'Standard rate', 'wp-graphql-woocommerce' ),
×
NEW
148
                        ];
×
149
                } else {
NEW
150
                        $tax_class = \WC_Tax::get_tax_class_by( 'slug', $slug );
×
NEW
151
                        return is_array( $tax_class ) && ! empty( $tax_class ) ? $tax_class : null;
×
152
                }
153
        }
154

155
        /**
156
         * Returns the tax rate connected the provided IDs.
157
         *
158
         * @param int $id - Tax rate IDs.
159
         *
160
         * @return \WPGraphQL\WooCommerce\Model\Tax_Rate|null
161
         */
162
        public function load_tax_rate_from_id( $id ) {
163
                global $wpdb;
14✔
164

165
                /**
166
                 * Get tax rate from WooCommerce.
167
                 *
168
                 * @var \stdClass&object{
169
                 *  tax_rate_id: int,
170
                 *  tax_rate_class: string,
171
                 *  tax_rate_country: string,
172
                 *  tax_rate_state: string,
173
                 *  tax_rate: string,
174
                 *  tax_rate_name: string,
175
                 *  tax_rate_priority: int,
176
                 *  tax_rate_compound: bool,
177
                 *  tax_rate_shipping: bool,
178
                 *  tax_rate_order: int,
179
                 *  tax_rate_city: string,
180
                 *  tax_rate_postcode: string,
181
                 *  tax_rate_postcodes: string,
182
                 *  tax_rate_cities: string
183
                 *  } $rate
184
                 */
185
                $rate = \WC_Tax::_get_tax_rate( $id, OBJECT );
14✔
186
                if ( ! empty( $rate ) && is_object( $rate ) ) {
14✔
187
                        $rate->tax_rate_city      = '';
14✔
188
                        $rate->tax_rate_postcode  = '';
14✔
189
                        $rate->tax_rate_postcodes = '';
14✔
190
                        $rate->tax_rate_cities    = '';
14✔
191

192
                        // Get locales from a tax rate.
193
                        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
194
                        $locales = $wpdb->get_results(
14✔
195
                                $wpdb->prepare(
14✔
196
                                        "
14✔
197
                                        SELECT location_code, location_type
198
                                        FROM {$wpdb->prefix}woocommerce_tax_rate_locations
14✔
199
                                        WHERE tax_rate_id = %d
200
                                        ",
14✔
201
                                        $rate->tax_rate_id
14✔
202
                                )
14✔
203
                        );
14✔
204

205
                        $cities    = [];
14✔
206
                        $postcodes = [];
14✔
207
                        foreach ( $locales as $locale ) {
14✔
208
                                if ( 'city' === $locale->location_type ) {
3✔
209
                                        $cities[] = $locale->location_code;
3✔
210
                                } elseif ( 'postcode' === $locale->location_type ) {
3✔
211
                                        $postcodes[] = $locale->location_code;
3✔
212
                                } else {
NEW
213
                                        $rate->{'tax_rate_' . $locale->location_type} = $locale->location_code;
×
214
                                }
215
                        }
216

217
                        if ( ! empty( $cities ) ) {
14✔
218
                                $rate->tax_rate_cities = implode( ';', $cities );
3✔
219
                                $rate->tax_rate_city   = end( $cities );
3✔
220
                        }
221

222
                        if ( ! empty( $postcodes ) ) {
14✔
223
                                $rate->tax_rate_postcodes = implode( ';', $postcodes );
3✔
224
                                $rate->tax_rate_postcode  = end( $postcodes );
3✔
225
                        }
226
                        return new Tax_Rate( $rate );
14✔
227
                } else {
228
                        return null;
×
229
                }//end if
230
        }
231

232
        /**
233
         * Returns the shipping method Model for the shipping method ID.
234
         *
235
         * @param int $id - Shipping method ID.
236
         *
237
         * @return \WPGraphQL\WooCommerce\Model\Shipping_Method
238
         *
239
         * @throws \GraphQL\Error\UserError Invalid object.
240
         */
241
        public function load_shipping_method_from_id( $id ) {
UNCOV
242
                $wc_shipping = \WC_Shipping::instance();
×
UNCOV
243
                $methods     = $wc_shipping->get_shipping_methods();
×
UNCOV
244
                if ( empty( $methods[ $id ] ) ) {
×
245
                        throw new UserError(
×
246
                        /* translators: shipping method ID */
247
                                sprintf( __( 'No Shipping Method assigned to ID %s was found ', 'wp-graphql-woocommerce' ), $id )
×
248
                        );
×
249
                }
250

UNCOV
251
                $method = $methods[ $id ];
×
252

UNCOV
253
                return new Shipping_Method( $method );
×
254
        }
255

256
        /**
257
         * Returns the shipping zone connected the provided IDs.
258
         *
259
         * @param int $id - Shipping zone IDs.
260
         *
261
         * @return \WPGraphQL\WooCommerce\Model\Shipping_Zone|null
262
         */
263
        public function load_shipping_zone_from_id( $id ) {
264
                /** @var \WC_Shipping_Zone|false $zone */
265
                $zone = \WC_Shipping_Zones::get_zone( $id );
10✔
266

267
                if ( false === $zone ) {
10✔
NEW
268
                        return null;
×
269
                }
270

271
                $zone = new Shipping_Zone( $zone );
10✔
272

273
                return $zone;
10✔
274
        }
275

276
        /**
277
         * Returns the order item connected the provided IDs.
278
         *
279
         * @param int $id - Order item IDs.
280
         *
281
         * @return \WPGraphQL\WooCommerce\Model\Order_Item|null
282
         */
283
        public function load_order_item_from_id( $id ) {
284
                $item = \WC()->order_factory::get_order_item( $id );
×
285

286
                if ( false === $item ) {
×
287
                        return null;
×
288
                }
289

290
                $item = new \WPGraphQL\WooCommerce\Model\Order_Item( $item );
×
291

292
                return $item;
×
293
        }
294
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc