Records
3 years ago
Catalog_Item.php
3 years ago
Interval_Polling.php
3 years ago
Job.php
3 years ago
Manual_Synchronization.php
3 years ago
Product_Import.php
3 years ago
Records.php
3 years ago
Stepped_Job.php
3 years ago
Records.php
393 lines
| 1 | <?php |
| 2 | /** |
| 3 | * WooCommerce Square |
| 4 | * |
| 5 | * This source file is subject to the GNU General Public License v3.0 |
| 6 | * that is bundled with this package in the file license.txt. |
| 7 | * It is also available through the world-wide-web at this URL: |
| 8 | * http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later |
| 9 | * If you did not receive a copy of the license and are unable to |
| 10 | * obtain it through the world-wide-web, please send an email |
| 11 | * to license@woocommerce.com so we can send you a copy immediately. |
| 12 | * |
| 13 | * DISCLAIMER |
| 14 | * |
| 15 | * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer |
| 16 | * versions in the future. If you wish to customize WooCommerce Square for your |
| 17 | * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/ |
| 18 | * |
| 19 | * @author WooCommerce |
| 20 | * @copyright Copyright: (c) 2019, Automattic, Inc. |
| 21 | * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later |
| 22 | */ |
| 23 | |
| 24 | namespace WooCommerce\Square\Sync; |
| 25 | |
| 26 | defined( 'ABSPATH' ) || exit; |
| 27 | |
| 28 | use WooCommerce\Square\Sync\Records\Record; |
| 29 | |
| 30 | /** |
| 31 | * The sync records handler. |
| 32 | * |
| 33 | * @since 2.0.0 |
| 34 | */ |
| 35 | class Records { |
| 36 | |
| 37 | |
| 38 | /** @var string WordPress option key where sync records are stored */ |
| 39 | private static $records_option_key = 'wc_square_sync_records'; |
| 40 | |
| 41 | |
| 42 | /** |
| 43 | * Checks if there are existing records. |
| 44 | * |
| 45 | * @since 2.0.0 |
| 46 | * |
| 47 | * @return bool |
| 48 | */ |
| 49 | public static function has_records() { |
| 50 | |
| 51 | return ! empty( self::has_records() ); |
| 52 | } |
| 53 | |
| 54 | |
| 55 | /** |
| 56 | * Gets a specific sync record. |
| 57 | * |
| 58 | * @since 2.0.0 |
| 59 | * |
| 60 | * @param int $id the record's identifier |
| 61 | * @return null|Record |
| 62 | */ |
| 63 | public static function get_record( $id ) { |
| 64 | |
| 65 | $records = self::get_records( array( 'id' => $id ) ); |
| 66 | |
| 67 | return ! empty( $records ) ? current( $records ) : null; |
| 68 | } |
| 69 | |
| 70 | |
| 71 | /** |
| 72 | * Gets an array of record objects. |
| 73 | * |
| 74 | * @since 2.0.0 |
| 75 | * |
| 76 | * @param array $args associative array of arguments to query records |
| 77 | * @return Record[] |
| 78 | */ |
| 79 | public static function get_records( array $args = array() ) { |
| 80 | |
| 81 | $args = wp_parse_args( |
| 82 | $args, |
| 83 | array( |
| 84 | 'id' => null, |
| 85 | 'type' => null, |
| 86 | 'product' => null, |
| 87 | 'orderby' => 'date', |
| 88 | 'sort' => 'DESC', |
| 89 | 'limit' => 50, |
| 90 | ) |
| 91 | ); |
| 92 | |
| 93 | $records = array(); |
| 94 | $raw_records = get_option( self::$records_option_key, array() ); |
| 95 | |
| 96 | foreach ( $raw_records as $raw_record_data ) { |
| 97 | |
| 98 | $record = new Record( $raw_record_data ); |
| 99 | |
| 100 | if ( ! empty( $args['id'] ) ) { |
| 101 | |
| 102 | $id = is_array( $args['id'] ) ? $args['id'] : explode( ',', $args['id'] ); |
| 103 | |
| 104 | if ( ! in_array( $record->get_id(), $id, false ) ) { |
| 105 | continue; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | if ( ! empty( $args['type'] ) ) { |
| 110 | |
| 111 | $type = is_array( $args['type'] ) ? $args['type'] : explode( ',', $args['type'] ); |
| 112 | |
| 113 | if ( ! $record->is_type( $type ) ) { |
| 114 | continue; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | if ( ! empty( $args['product'] ) ) { |
| 119 | |
| 120 | $product = is_array( $args['product'] ) ? $args['product'] : explode( ',', $args['product'] ); |
| 121 | |
| 122 | if ( ! in_array( $record->get_product_id(), $product, false ) ) { |
| 123 | continue; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | $records[ $record->get_id() ] = $record; |
| 128 | } |
| 129 | |
| 130 | if ( ! empty( $records ) ) { |
| 131 | |
| 132 | switch ( $args['orderby'] ) { |
| 133 | case 'date': |
| 134 | uasort( $records, array( 'self', 'sort_records_by_date' ) ); |
| 135 | break; |
| 136 | case 'type': |
| 137 | uasort( $records, array( 'self', 'sort_records_by_type' ) ); |
| 138 | break; |
| 139 | } |
| 140 | |
| 141 | if ( 'DESC' === $args['sort'] ) { |
| 142 | $records = array_reverse( $records, true ); |
| 143 | } |
| 144 | |
| 145 | $records = array_slice( $records, 0, max( 50, absint( $args['limit'] ) ) ); |
| 146 | } |
| 147 | |
| 148 | return $records; |
| 149 | } |
| 150 | |
| 151 | |
| 152 | /** |
| 153 | * Compares two records for sorting by date. |
| 154 | * |
| 155 | * @see usort() callback |
| 156 | * @see Records::get_records() |
| 157 | * |
| 158 | * @since 2.0.0 |
| 159 | * |
| 160 | * @param Record $record_1 first record |
| 161 | * @param Record $record_2 second record |
| 162 | * @return int should return 0, -1 or +1 |
| 163 | */ |
| 164 | private static function sort_records_by_date( $record_1, $record_2 ) { |
| 165 | |
| 166 | $compare = 0; |
| 167 | |
| 168 | if ( $record_1 instanceof Record && $record_2 instanceof Record ) { |
| 169 | |
| 170 | $timestamp_1 = $record_1->get_timestamp(); |
| 171 | $timestamp_2 = $record_2->get_timestamp(); |
| 172 | |
| 173 | if ( $timestamp_1 > $timestamp_2 ) { |
| 174 | $compare = 1; |
| 175 | } elseif ( $timestamp_1 < $timestamp_2 ) { |
| 176 | $compare = -1; |
| 177 | } else { // compare by ID as a fallback to keep order consistency |
| 178 | $compare = strnatcmp( $record_1->get_id(), $record_2->get_id() ); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | return $compare; |
| 183 | } |
| 184 | |
| 185 | |
| 186 | /** |
| 187 | * Compares two records for sorting by type. |
| 188 | * |
| 189 | * @see usort() callback |
| 190 | * @see Records::get_records() |
| 191 | * |
| 192 | * @since 2.0.0 |
| 193 | * |
| 194 | * @param Record $record_1 first record |
| 195 | * @param Record $record_2 second record |
| 196 | * @return int should return 0, -1 or +1 |
| 197 | */ |
| 198 | private static function sort_records_by_type( $record_1, $record_2 ) { |
| 199 | |
| 200 | $compare = 0; |
| 201 | |
| 202 | if ( $record_1 instanceof Record && $record_2 instanceof Record ) { |
| 203 | |
| 204 | $compare = strnatcmp( $record_1->get_type(), $record_2->get_type() ); |
| 205 | |
| 206 | // if they are equal, sort by date within the same type group |
| 207 | if ( 0 === $compare ) { |
| 208 | |
| 209 | $timestamp_1 = $record_1->get_timestamp(); |
| 210 | $timestamp_2 = $record_2->get_timestamp(); |
| 211 | |
| 212 | if ( $timestamp_1 > $timestamp_2 ) { |
| 213 | $compare = 1; |
| 214 | } elseif ( $timestamp_1 < $timestamp_2 ) { |
| 215 | $compare = -1; |
| 216 | } else { // compare by ID as a fallback to keep order consistency |
| 217 | $compare = strnatcmp( $record_1->get_id(), $record_2->get_id() ); |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | return $compare; |
| 223 | } |
| 224 | |
| 225 | |
| 226 | /** |
| 227 | * Saves a new record. |
| 228 | * |
| 229 | * @since 2.0.0 |
| 230 | * |
| 231 | * @param array|Record $data raw data or record object |
| 232 | * @return bool success |
| 233 | */ |
| 234 | public static function set_record( $data ) { |
| 235 | |
| 236 | if ( is_array( $data ) ) { |
| 237 | $new_record = new Record( $data ); |
| 238 | } else { |
| 239 | $new_record = $data; |
| 240 | } |
| 241 | |
| 242 | if ( $new_record instanceof Record ) { |
| 243 | |
| 244 | // ensures there are never more than 50 records, leaving behind the older ones |
| 245 | $existing_records = self::get_records( array( 'limit' => 49 ) ); |
| 246 | $raw_records = array(); |
| 247 | |
| 248 | foreach ( $existing_records as $existing_record ) { |
| 249 | $raw_records[ $existing_record->get_id() ] = $existing_record->get_data(); |
| 250 | } |
| 251 | |
| 252 | $raw_records[ $new_record->get_id() ] = $new_record->get_data(); |
| 253 | |
| 254 | $success = update_option( self::$records_option_key, $raw_records ); |
| 255 | |
| 256 | } else { |
| 257 | |
| 258 | $success = false; |
| 259 | } |
| 260 | |
| 261 | return $success; |
| 262 | } |
| 263 | |
| 264 | |
| 265 | /** |
| 266 | * Saves multiple records. |
| 267 | * |
| 268 | * @since 2.0.0 |
| 269 | * |
| 270 | * @param array|Record[] $data array of raw record data or array of record objects |
| 271 | * @return bool success |
| 272 | */ |
| 273 | public static function set_records( array $data ) { |
| 274 | |
| 275 | $success = false; |
| 276 | $raw_records = array(); |
| 277 | |
| 278 | foreach ( $data as $record ) { |
| 279 | |
| 280 | if ( is_array( $record ) ) { |
| 281 | $record = new Record( $record ); |
| 282 | } |
| 283 | |
| 284 | if ( $record instanceof Record ) { |
| 285 | $raw_records[ $record->get_id() ] = $record->get_data(); |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | if ( ! empty( $raw_records ) ) { |
| 290 | |
| 291 | $records = self::get_records( array( 'limit' => 50 - count( $raw_records ) ) ); |
| 292 | |
| 293 | foreach ( $records as $record ) { |
| 294 | $raw_records[ $record->get_id() ] = $record->get_data(); |
| 295 | } |
| 296 | |
| 297 | $success = update_option( self::$records_option_key, $raw_records ); |
| 298 | } |
| 299 | |
| 300 | return $success; |
| 301 | } |
| 302 | |
| 303 | |
| 304 | /** |
| 305 | * Removes a record permanently. |
| 306 | * |
| 307 | * @since 2.0.0 |
| 308 | * |
| 309 | * @param int $id record identifier |
| 310 | * @return bool success |
| 311 | */ |
| 312 | public static function delete_record( $id ) { |
| 313 | |
| 314 | $success = false; |
| 315 | $raw_records = get_option( self::$records_option_key, array() ); |
| 316 | |
| 317 | if ( array_key_exists( $id, $raw_records ) ) { |
| 318 | |
| 319 | unset( $raw_records[ $id ] ); |
| 320 | |
| 321 | $success = update_option( self::$records_option_key, $raw_records ); |
| 322 | } |
| 323 | |
| 324 | return $success; |
| 325 | } |
| 326 | |
| 327 | |
| 328 | /** |
| 329 | * Delete multiple records. |
| 330 | * |
| 331 | * @since 2.0.0 |
| 332 | * |
| 333 | * @param array $args query arguments |
| 334 | * @return int count of records removed |
| 335 | */ |
| 336 | public static function delete_records( array $args ) { |
| 337 | |
| 338 | $removed = 0; |
| 339 | $raw_records = get_option( self::$records_option_key, array() ); |
| 340 | |
| 341 | foreach ( $raw_records as $raw_record ) { |
| 342 | |
| 343 | $record = new Record( $raw_record ); |
| 344 | |
| 345 | if ( isset( $args['id'] ) ) { |
| 346 | |
| 347 | $id = is_array( $args['id'] ) ? $args['id'] : explode( ',', $args['id'] ); |
| 348 | |
| 349 | if ( in_array( $record->get_id(), $id, false ) ) { |
| 350 | unset( $raw_records[ $record->get_id() ] ); |
| 351 | $removed++; |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | if ( isset( $args['type'] ) ) { |
| 356 | |
| 357 | $type = $args['type']; |
| 358 | |
| 359 | if ( $record->is_type( $type ) ) { |
| 360 | unset( $raw_records[ $record->get_id() ] ); |
| 361 | $removed++; |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | if ( $removed > 0 ) { |
| 367 | |
| 368 | $success = update_option( self::$records_option_key, $raw_records ); |
| 369 | |
| 370 | if ( ! $success ) { |
| 371 | $removed = 0; |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | return $removed; |
| 376 | } |
| 377 | |
| 378 | |
| 379 | /** |
| 380 | * Removes all records. |
| 381 | * |
| 382 | * @since 2.0.0 |
| 383 | * |
| 384 | * @return bool |
| 385 | */ |
| 386 | public static function clean_records() { |
| 387 | |
| 388 | return update_option( self::$records_option_key, array() ); |
| 389 | } |
| 390 | |
| 391 | |
| 392 | } |
| 393 |