Completed
Push — master ( 05179e...154915 )
by Mike
07:48
created

WC_Shipping_Zone::set_zone_order()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 16 and the first side effect is on line 4.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit;
5
}
6
7
/**
8
 * Represents a single shipping zone
9
 *
10
 * @class 		WC_Shipping_Zone
11
 * @version		2.6.0
12
 * @package		WooCommerce/Classes
13
 * @category	Class
14
 * @author 		WooThemes
15
 */
16
class WC_Shipping_Zone implements WC_Data {
17
18
	/**
19
	 * Zone Data
20
	 * @var array
21
	 */
22
    private $data = array(
23
		'zone_id'        => 0,
24
		'zone_name'      => '',
25
		'zone_order'     => 0,
26
		'zone_locations' => array()
27
	);
28
29
	/**
30
	 * True when location data needs to be re-saved
31
	 * @var bool
32
	 */
33
	private $_locations_changed = false;
34
35
	/**
36
	 * Constructor for zones
37
	 * @param int|object $zone Zone ID to load from the DB (optional) or already queried data.
38
	 */
39
    public function __construct( $zone = 0 ) {
40
		if ( is_numeric( $zone ) && ! empty( $zone ) ) {
41
        	$this->read( $zone );
42
		} elseif ( is_object( $zone ) ) {
43
			$this->set_zone_id( $zone->zone_id );
44
			$this->set_zone_name( $zone->zone_name );
45
			$this->set_zone_order( $zone->zone_order );
46
			$this->read_zone_locations( $zone->zone_id );
47
		} elseif ( 0 === $zone ) {
48
			$this->set_zone_name( __( 'Rest of the World', 'woocommerce' ) );
49
			$this->read_zone_locations( 0 );
50
		}
51
    }
52
53
	/**
54
	 * Get ID
55
	 * @return int
56
	 */
57
    public function get_id() {
58
        return $this->get_zone_id();
59
    }
60
61
	/**
62
	 * Get class data array
63
	 * @return array
64
	 */
65
	public function get_data() {
66
		return $this->data;
67
	}
68
69
	/**
70
     * Insert zone into the database
71
     */
72
    public function create() {
73
		global $wpdb;
74
		$wpdb->insert( $wpdb->prefix . 'woocommerce_shipping_zones', array(
75
			'zone_name'  => $this->get_zone_name(),
76
			'zone_order' => $this->get_zone_order(),
77
		) );
78
		$this->set_zone_id( $wpdb->insert_id );
79
	}
80
81
	/**
82
	 * Read zone.
83
	 * @param int ID to read from DB
84
	 */
85
	public function read( $id ) {
86
		global $wpdb;
87
88
		if ( $zone_data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zones WHERE zone_id = %d LIMIT 1;", $id ) ) ) {
89
			$this->set_zone_id( $zone_data->zone_id );
90
			$this->set_zone_name( $zone_data->zone_name );
91
			$this->set_zone_order( $zone_data->zone_order );
92
			$this->read_zone_locations( $zone_data->zone_id );
93
		}
94
	}
95
96
    /**
97
     * Update zone in the database
98
     */
99
    public function update() {
100
        global $wpdb;
101
		$wpdb->update( $wpdb->prefix . 'woocommerce_shipping_zones', array(
102
			'zone_name'  => $this->get_zone_name(),
103
			'zone_order' => $this->get_zone_order(),
104
		), array( 'zone_id' => $this->get_zone_id() ) );
105
    }
106
107
	/**
108
	 * Delete a zone.
109
	 * @since 2.6.0
110
	 */
111
    public function delete() {
112
		if ( $this->get_id() ) {
113
			global $wpdb;
114
			$wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_methods', array( 'zone_id' => $this->get_id() ) );
115
	        $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array( 'zone_id' => $this->get_id() ) );
116
			$wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zones', array( 'zone_id' => $this->get_id() ) );
117
			WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
118
			$this->set_zone_id( 0 );
119
		}
120
    }
121
122
	/**
123
	 * Save zone data to the database.
124
	 */
125
	public function save() {
126
		if ( ! $this->get_zone_id() ) {
127
			$this->create();
128
		} else {
129
			$this->update();
130
		}
131
132
		$this->save_locations();
133
		WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
134
135
		// Increments the transient version to invalidate cache.
136
		WC_Cache_Helper::get_transient_version( 'shipping', true );
137
	}
138
139
	/**
140
	 * Get zone ID
141
	 * @return int
142
	 */
143
    public function get_zone_id() {
144
        return absint( $this->data['zone_id'] );
145
    }
146
147
	/**
148
	 * Get zone name
149
	 * @return string
150
	 */
151
    public function get_zone_name() {
152
        return $this->data['zone_name'];
153
    }
154
155
	/**
156
	 * Get zone order
157
	 * @return int
158
	 */
159
	public function get_zone_order() {
160
        return absint( $this->data['zone_order'] );
161
    }
162
163
	/**
164
	 * Get zone locations
165
	 * @return array of zone objects
166
	 */
167
	public function get_zone_locations() {
168
        return $this->data['zone_locations'];
169
    }
170
171
	/**
172
	 * Return a text string representing what this zone is for.
173
	 * @return string
174
	 */
175
	public function get_formatted_location( $max = 10 ) {
176
		$location_parts = array();
177
		$all_continents = WC()->countries->get_continents();
178
		$all_countries  = WC()->countries->get_countries();
179
		$all_states     = WC()->countries->get_states();
180
		$locations      = $this->get_zone_locations();
181
		$continents     = array_filter( $locations, array( $this, 'location_is_continent' ) );
182
		$countries      = array_filter( $locations, array( $this, 'location_is_country' ) );
183
		$states         = array_filter( $locations, array( $this, 'location_is_state' ) );
184
		$postcodes      = array_filter( $locations, array( $this, 'location_is_postcode' ) );
185
186
		foreach ( $continents as $location ) {
187
			$location_parts[] = $all_continents[ $location->code ]['name'];
188
		}
189
190
		foreach ( $countries as $location ) {
191
			$location_parts[] = $all_countries[ $location->code ];
192
		}
193
194
		foreach ( $states as $location ) {
195
			$location_codes = explode( ':', $location->code );
196
			$location_parts[] = $all_states[ $location_codes[ 0 ] ][ $location_codes[ 1 ] ];
197
		}
198
199
		foreach ( $postcodes as $location ) {
200
			$location_parts[] = $location->code;
201
		}
202
203
		// Fix display of encoded characters.
204
		$location_parts = array_map( 'html_entity_decode', $location_parts );
205
206
		if ( sizeof( $location_parts ) > $max ) {
207
			$remaining = sizeof( $location_parts ) - $max;
208
			return sprintf( _n( '%s and %d other region', '%s and %d other regions', $remaining, 'woocommerce' ), implode( ', ', array_splice( $location_parts, 0, $max ) ), $remaining );
209
		} else {
210
			return implode( ', ', $location_parts );
211
		}
212
	}
213
214
	/**
215
	 * Get shipping methods linked to this zone
216
	 * @param bool Only return enabled methods.
217
	 * @return array of objects
218
	 */
219
	public function get_shipping_methods( $enabled_only = false ) {
220
		global $wpdb;
221
222
		$raw_methods_sql = $enabled_only ? "SELECT method_id, method_order, instance_id, is_enabled FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d AND is_enabled = 1 order by method_order ASC;" : "SELECT method_id, method_order, instance_id, is_enabled FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d order by method_order ASC;";
223
        $raw_methods     = $wpdb->get_results( $wpdb->prepare( $raw_methods_sql, $this->get_zone_id() ) );
224
		$wc_shipping     = WC_Shipping::instance();
225
		$allowed_classes = $wc_shipping->get_shipping_method_class_names();
226
		$methods         = array();
227
228
		foreach ( $raw_methods as $raw_method ) {
229
			if ( in_array( $raw_method->method_id, array_keys( $allowed_classes ) ) ) {
230
				$class_name = $allowed_classes[ $raw_method->method_id ];
231
232
				// The returned array may contain instances of shipping methods, as well
233
				// as classes. If the "class" is an instance, just use it. If not,
234
				// create an instance.
235
				if ( is_object( $class_name ) ) {
236
					$class_name_of_instance = get_class( $class_name );
237
					$methods[ $raw_method->instance_id ] = new $class_name_of_instance( $raw_method->instance_id );
238
				} else {
239
					// If the class is not an object, it should be a string. It's better
240
					// to double check, to be sure (a class must be a string, anything)
241
					// else would be useless
242
					if ( is_string( $class_name ) && class_exists( $class_name ) ) {
243
						$methods[ $raw_method->instance_id ] = new $class_name( $raw_method->instance_id );
244
					}
245
				}
246
247
				// Let's make sure that we have an instance before setting its attributes
248
				if ( is_object( $methods[ $raw_method->instance_id ] ) ) {
249
					$methods[ $raw_method->instance_id ]->method_order = absint( $raw_method->method_order );
250
					$methods[ $raw_method->instance_id ]->enabled      = $raw_method->is_enabled ? 'yes' : 'no';
251
					$methods[ $raw_method->instance_id ]->has_settings = $methods[ $raw_method->instance_id ]->has_settings();
252
				}
253
			}
254
		}
255
256
		return apply_filters( 'woocommerce_shipping_zone_shipping_methods', $methods, $raw_methods, $allowed_classes, $this );
257
	}
258
259
	/**
260
	 * Location type detection
261
	 * @param  object  $location
262
	 * @return boolean
263
	 */
264
	private function location_is_continent( $location ) {
265
		return 'continent' === $location->type;
266
	}
267
268
	/**
269
	 * Location type detection
270
	 * @param  object  $location
271
	 * @return boolean
272
	 */
273
	private function location_is_country( $location ) {
274
		return 'country' === $location->type;
275
	}
276
277
	/**
278
	 * Location type detection
279
	 * @param  object  $location
280
	 * @return boolean
281
	 */
282
	private function location_is_state( $location ) {
283
		return 'state' === $location->type;
284
	}
285
286
	/**
287
	 * Location type detection
288
	 * @param  object  $location
289
	 * @return boolean
290
	 */
291
	private function location_is_postcode( $location ) {
292
		return 'postcode' === $location->type;
293
	}
294
295
	/**
296
	 * Set zone ID
297
	 * @access private
298
	 * @param int $set
299
	 */
300
    private function set_zone_id( $set ) {
301
        $this->data['zone_id'] = absint( $set );
302
    }
303
304
	/**
305
	 * Set zone name
306
	 * @param string $set
307
	 */
308
    public function set_zone_name( $set ) {
309
		$this->data['zone_name'] = wc_clean( $set );
310
    }
311
312
	/**
313
	 * Set zone order
314
	 * @param int $set
315
	 */
316
	public function set_zone_order( $set ) {
317
        $this->data['zone_order'] = absint( $set );
318
    }
319
320
	/**
321
	 * Is passed location type valid?
322
	 * @param  string  $type
323
	 * @return boolean
324
	 */
325
	public function is_valid_location_type( $type ) {
326
		return in_array( $type, array( 'postcode', 'state', 'country', 'continent' ) );
327
	}
328
329
	/**
330
	 * Add location (state or postcode) to a zone.
331
	 * @param string $code
332
	 * @param string $type state or postcode
333
	 */
334
	public function add_location( $code, $type ) {
335
		if ( $this->is_valid_location_type( $type ) ) {
336
			$location = array(
337
				'code' => wc_clean( $code ),
338
				'type' => wc_clean( $type )
339
			);
340
			$this->data['zone_locations'][] = (object) $location;
341
			$this->_locations_changed = true;
342
		}
343
	}
344
345
	/**
346
	 * Clear all locations for this zone.
347
	 * @param array|string $types of location to clear
348
	 */
349
	public function clear_locations( $types = array( 'postcode', 'state', 'country', 'continent' ) ) {
350
		if ( ! is_array( $types ) ) {
351
			$types = array( $types );
352
		}
353
		foreach ( $this->data['zone_locations'] as $key => $values ) {
354
			if ( in_array( $values->type, $types ) ) {
355
				unset( $this->data['zone_locations'][ $key ] );
356
				$this->_locations_changed = true;
357
			}
358
		}
359
	}
360
361
	/**
362
	 * Set locations
363
	 * @param array $locations Array of locations
364
	 */
365
	public function set_locations( $locations = array() ) {
366
		$this->clear_locations();
367
368
		foreach ( $locations as $location ) {
369
			$this->add_location( $location['code'], $location['type'] );
370
		}
371
372
		$this->_locations_changed = true;
373
	}
374
375
	/**
376
	 * Read location data from the database
377
	 * @param  int $zone_id
378
	 */
379
	private function read_zone_locations( $zone_id ) {
380
		global $wpdb;
381
382
		if ( $locations = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE zone_id = %d;", $zone_id ) ) ) {
383
			foreach ( $locations as $location ) {
384
				$this->add_location( $location->location_code, $location->location_type );
385
			}
386
		}
387
		$this->_locations_changed = false;
388
	}
389
390
	/**
391
	 * Save locations to the DB.
392
	 *
393
	 * This function clears old locations, then re-inserts new if any changes are found.
394
	 */
395
	private function save_locations() {
396
		if ( ! $this->get_zone_id() || ! $this->_locations_changed ) {
397
			return false;
398
		}
399
		global $wpdb;
400
		$wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array( 'zone_id' => $this->get_zone_id() ) );
401
402
		foreach ( $this->get_zone_locations() as $location ) {
403
			$wpdb->insert( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array(
404
				'zone_id'       => $this->get_zone_id(),
405
				'location_code' => $location->code,
406
				'location_type' => $location->type
407
			) );
408
		}
409
	}
410
411
	/**
412
	 * Add a shipping method to this zone.
413
	 * @param string $type shipping method type
414
	 * @return int new instance_id, 0 on failure
415
	 */
416
	public function add_shipping_method( $type ) {
417
		global $wpdb;
418
419
		$instance_id     = 0;
420
		$wc_shipping     = WC_Shipping::instance();
421
		$allowed_classes = $wc_shipping->get_shipping_method_class_names();
422
423
		if ( in_array( $type, array_keys( $allowed_classes ) ) ) {
424
			$wpdb->insert(
425
				$wpdb->prefix . 'woocommerce_shipping_zone_methods',
426
				array(
427
					'method_id'    => $type,
428
					'zone_id'      => $this->get_zone_id(),
429
					'method_order' => 0
430
				),
431
				array(
432
					'%s',
433
					'%d',
434
					'%d'
435
				)
436
			);
437
			$instance_id = $wpdb->insert_id;
438
		}
439
440
		return $instance_id;
441
	}
442
}
443