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

wp-graphql / wp-graphql-woocommerce / 14788432316

01 May 2025 06:46PM UTC coverage: 83.59% (-0.03%) from 83.617%
14788432316

push

github

web-flow
Fix/recursive interface definitions (#934)

* fix: recursive interface definitions for Product, etc.

* devops: CI & Linter compliances met

* devops: lint-code.yml updated

---------

Co-authored-by: Geoff Taylor <geoff@axistaylor.com>

7 of 9 new or added lines in 8 files covered. (77.78%)

8 existing lines in 2 files now uncovered.

12424 of 14863 relevant lines covered (83.59%)

72.08 hits per line

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

0.0
/includes/data/cursor/class-cot-cursor.php
1
<?php
2
/**
3
 * COT Cursor
4
 *
5
 * This class generates the SQL AND operators for cursor based pagination
6
 * for the custom orders table/HPOS
7
 *
8
 * @package WPGraphQL\WooCommerce\Data\Cursor;
9
 * @since   0.14.0
10
 */
11

12
namespace WPGraphQL\WooCommerce\Data\Cursor;
13

14
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
15
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableMetaQuery;
16
use WPGraphQL\Data\Cursor\AbstractCursor;
17

18
/**
19
 * Class COT_Cursor
20
 */
21
class COT_Cursor extends AbstractCursor {
22
        /**
23
         * Stores the cursory order node
24
         *
25
         * @var ?\WC_Abstract_Order
26
         */
27
        public $cursor_node;
28

29
        /**
30
         * Counter for meta value joins
31
         *
32
         * @var integer
33
         */
34
        public $meta_join_alias = 0;
35

36
        /**
37
         * The query instance to use when building the SQL statement.
38
         *
39
         * @var \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableQuery
40
         */
41
        public $query;
42

43
        /**
44
         * Names of all COT tables (orders, addresses, operational_data, meta) in the form 'table_id' => 'table name'.
45
         *
46
         * @var array
47
         */
48
        private $tables;
49

50
        /**
51
         * Undocumented variable
52
         *
53
         * @var array
54
         */
55
        private $column_mappings;
56

57
        /**
58
         * Meta query parser.
59
         *
60
         * @var \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableMetaQuery|null
61
         */
62
        private $meta_query;
63

64
        /**
65
         * COT_Cursor constructor.
66
         *
67
         * @param array                                                               $query_vars  The query vars to use when building the SQL statement.
68
         * @param \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableQuery $query       The query to use when building the SQL statement.
69
         * @param string|null                                                         $cursor      Whether to generate the before or after cursor. Default "after".
70
         */
71
        public function __construct( $query_vars, $query, $cursor = 'after' ) {
72
                // Initialize the class properties.
73
                parent::__construct( $query_vars, $cursor );
×
74

75
                $this->query = $query;
×
76

77
                // Get tables.
78
                /** @var \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore $order_datastore */
79
                $order_datastore       = wc_get_container()->get( OrdersTableDataStore::class );
×
80
                $this->tables          = $order_datastore::get_all_table_names_with_id();
×
81
                $mappings              = $order_datastore->get_all_order_column_mappings();
×
82
                $this->column_mappings = [];
×
83
                foreach ( $mappings['orders'] as $column => $meta_value ) {
×
84
                        $this->column_mappings[ "{$this->tables['orders']}.{$column}" ] = $meta_value['name'];
×
85
                }
86

87
                if ( ! is_null( $this->get_query_var( 'meta_query' ) ) ) {
×
88
                        $this->meta_query = new OrdersTableMetaQuery( $this->query );
×
89
                }
90
        }
91

92
        /**
93
         * {@inheritDoc}
94
         *
95
         * @return ?\WC_Abstract_Order
96
         */
97
        public function get_cursor_node() {
98
                // If we have a bad cursor, just skip.
99
                if ( ! $this->cursor_offset ) {
×
100
                        return null;
×
101
                }
102

103
                // Get the order.
104
                $order = wc_get_order( $this->cursor_offset );
×
105

106
                return $order instanceof \WC_Abstract_Order ? $order : null;
×
107
        }
108

109
        /**
110
         * {@inheritDoc}
111
         */
112
        public function to_sql() {
113
                $orderby = isset( $this->query_vars['orderby'] ) ? $this->query_vars['orderby'] : null;
×
114

115
                $orderby_should_not_convert_to_sql = isset( $orderby ) && in_array(
×
116
                        $orderby,
×
117
                        [
×
118
                                'include',
×
119
                                'id',
×
120
                                'parent_order_id',
×
121
                        ],
×
122
                        true
×
123
                );
×
124

125
                if ( true === $orderby_should_not_convert_to_sql ) {
×
126
                        return '';
×
127
                }
128

129
                $sql = $this->builder->to_sql();
×
130

131
                if ( empty( $sql ) ) {
×
132
                        return '';
×
133
                }
134

135
                return ' AND ' . $sql;
×
136
        }
137

138
        /**
139
         * {@inheritDoc}
140
         */
141
        public function get_where() {
142
                // If we have a bad cursor, just skip.
143
                if ( ! $this->is_valid_offset_and_node() ) {
×
144
                        return '';
×
145
                }
146

147
                $orderby = $this->get_query_var( 'orderby' );
×
148
                $order   = $this->get_query_var( 'order' );
×
149

150
                if ( ! empty( $orderby ) && is_array( $orderby ) ) {
×
151

152
                        /**
153
                         * Loop through all order keys if it is an array
154
                         */
155
                        foreach ( $orderby as $by => $order ) {
×
156
                                $this->compare_with( $by, $order );
×
157
                        }
158
                } elseif ( ! empty( $orderby ) && is_string( $orderby ) ) {
×
159

160
                        /**
161
                         * If $orderby is just a string just compare with it directly as DESC
162
                         */
163
                        $this->compare_with( $orderby, $order );
×
164
                }
165

166
                /**
167
                 * No custom comparing. Use the default date
168
                 */
169
                if ( ! $this->builder->has_fields() ) {
×
170
                        $this->compare_with_date();
×
171
                }
172

173
                $this->builder->add_field( "{$this->tables['orders']}.id", $this->cursor_offset, 'ID', $order );
×
174

175
                return $this->to_sql();
×
176
        }
177

178
        /**
179
         * Get AND operator for given order by key
180
         *
181
         * @param string $by    The order by key.
182
         * @param string $order The order direction ASC or DESC.
183
         *
184
         * @return void
185
         */
186
        private function compare_with( $by, $order ) {
187
                if ( null === $this->cursor_node ) {
×
188
                        return;
×
189
                }
190

191
                $meta_orderby_keys = $this->meta_query ? $this->meta_query->get_orderby_keys() : [];
×
192

193
                if ( in_array( $by, $meta_orderby_keys, true ) && null !== $this->meta_query ) {
×
194
                        $orderby = $this->meta_query->get_orderby_clause_for_key( $by );
×
195
                        $value   = $this->cursor_node->get_meta( $by, true ) ?? null;
×
196
                } else {
197
                        $orderby     = $by;
×
198
                        $getter_name = $this->column_mappings[ $orderby ];
×
199

200
                        $method = "get_{$getter_name}";
×
201
                        $value  = is_callable( [ $this->cursor_node, $method ] ) ? $this->cursor_node->$method() : null;
×
202
                }
203

204
                if ( ! empty( $value ) && is_a( $value, '\WC_DateTime' ) ) {
×
205
                        $value = ( new \DateTime( $value ) )->setTimezone( new \DateTimeZone( '+00:00' ) )->format( 'Y-m-d H:i:s' );
×
206
                        $this->builder->add_field( $by, $value, 'DATETIME', $order );
×
207
                        return;
×
208
                }
209

210
                /**
211
                 * Compare by the post field if the key matches a value
212
                 */
213
                if ( ! empty( $value ) ) {
×
214
                        $this->builder->add_field( $by, $value, null, $order );
×
215
                }
216
        }
217

218
        /**
219
         * Use post date based comparison
220
         *
221
         * @return void
222
         */
223
        private function compare_with_date() {
224
                $value = null;
×
225
                if ( null !== $this->cursor_node ) {
×
226
                        $date_created = $this->cursor_node->get_date_created();
×
227
                        $value        = ! empty( $date_created ) ? ( new \DateTime( $date_created ) )->setTimezone( new \DateTimeZone( '+00:00' ) )->format( 'Y-m-d H:i:s' ) : null;
×
228
                }
229

230
                $this->builder->add_field( "{$this->tables['orders']}.date_created_gmt", $value, 'DATETIME' );
×
231
        }
232
}
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