Completed
Push — master ( 09e43c...a8e479 )
by Mike
11:28
created

send_stock_notifications()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Legacy Abstract Order
8
 *
9
 * Legacy and deprecated functions are here to keep the WC_Abstract_Order clean.
10
 * This class will be removed in future versions.
11
 *
12
 * @version	 2.7.0
13
 * @package	 WooCommerce/Abstracts
14
 * @category	Abstract Class
15
 * @author	  WooThemes
16
 */
17
abstract class WC_Abstract_Legacy_Order extends WC_Data {
18
19
	/**
20
	 * Add coupon code to the order.
21
	 * @param string $code
22
	 * @param int $discount tax amount.
23
	 * @param int $discount_tax amount.
24
	 * @return int order item ID
25
	 */
26
	public function add_coupon( $code = array(), $discount = 0, $discount_tax = 0 ) {
27
		_deprecated_function( 'WC_Order::add_coupon', '2.7', 'Create new WC_Order_Item_Coupon object and add to order with WC_Order::add_item()' );
28
29
		$item = new WC_Order_Item_Coupon( array(
0 ignored issues
show
Documentation introduced by
array('code' => $code, '...id' => $this->get_id()) is of type array<string,string|arra...,"order_id":"integer"}>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
30
			'code'         => $code,
31
			'discount'     => $discount,
32
			'discount_tax' => $discount_tax,
33
			'order_id'     => $this->get_id(),
34
		) );
35
		$item->save();
36
		$this->add_item( $item );
37
		wc_do_deprecated_action( 'woocommerce_order_add_coupon', array( $this->get_id(), $item->get_id(), $code, $discount, $discount_tax ), '2.7', 'Use woocommerce_new_order_item action instead.' );
38
		return $item->get_id();
39
	}
40
41
	/**
42
	 * Add a tax row to the order.
43
	 * @param array $args
0 ignored issues
show
Bug introduced by
There is no parameter named $args. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
44
	 * @param int $tax_amount amount of tax.
45
	 * @param int $shipping_tax_amount shipping amount.
46
	 * @return int order item ID
47
	 */
48
	public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
49
		_deprecated_function( 'WC_Order::add_tax', '2.7', 'Create new WC_Order_Item_Tax object and add to order with WC_Order::add_item()' );
50
51
		$item = new WC_Order_Item_Tax( array(
0 ignored issues
show
Documentation introduced by
array('rate_id' => $tax_...> $shipping_tax_amount) is of type array<string,?,{"rate_id..._tax_total":"integer"}>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
52
			'rate_id'            => $tax_rate_id,
53
			'tax_total'          => $tax_amount,
54
			'shipping_tax_total' => $shipping_tax_amount,
55
		) );
56
		$item->set_rate( $tax_rate_id );
57
		$item->set_order_id( $this->get_id() );
58
		$item->save();
59
		$this->add_item( $item );
60
		wc_do_deprecated_action( 'woocommerce_order_add_tax', array( $this->get_id(), $item->get_id(), $tax_rate_id, $tax_amount, $shipping_tax_amount ), '2.7', 'Use woocommerce_new_order_item action instead.' );
61
		return $item->get_id();
62
	}
63
64
	/**
65
	 * Add a shipping row to the order.
66
	 * @param WC_Shipping_Rate shipping_rate
67
	 * @return int order item ID
68
	 */
69
	public function add_shipping( $shipping_rate ) {
70
		_deprecated_function( 'WC_Order::add_shipping', '2.7', 'Create new WC_Order_Item_Shipping object and add to order with WC_Order::add_item()' );
71
72
		$item = new WC_Order_Item_Shipping( array(
0 ignored issues
show
Documentation introduced by
array('method_title' => ...id' => $this->get_id()) is of type array<string,?,{"method_...,"order_id":"integer"}>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
73
			'method_title' => $shipping_rate->label,
74
			'method_id'    => $shipping_rate->id,
75
			'total'        => wc_format_decimal( $shipping_rate->cost ),
76
			'taxes'        => $shipping_rate->taxes,
77
			'meta_data'    => $shipping_rate->get_meta_data(),
78
			'order_id'     => $this->get_id(),
79
		) );
80
		$item->save();
81
		$this->add_item( $item );
82
		wc_do_deprecated_action( 'woocommerce_order_add_shipping', array( $this->get_id(), $item->get_id(), $shipping_rate ), '2.7', 'Use woocommerce_new_order_item action instead.' );
83
		return $item->get_id();
84
	}
85
86
	/**
87
	 * Add a fee to the order.
88
	 * Order must be saved prior to adding items.
89
	 * @param object $fee
90
	 * @return int updated order item ID
91
	 */
92
	public function add_fee( $fee ) {
93
		_deprecated_function( 'WC_Order::add_fee', '2.7', 'Create new WC_Order_Item_Fee object and add to order with WC_Order::add_item()' );
94
95
		$item = new WC_Order_Item_Fee( array(
0 ignored issues
show
Documentation introduced by
array('name' => $fee->na...id' => $this->get_id()) is of type array<string,?,{"name":"...,"order_id":"integer"}>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
96
			'name'      => $fee->name,
97
			'tax_class' => $fee->taxable ? $fee->tax_class : 0,
98
			'total'     => $fee->amount,
99
			'total_tax' => $fee->tax,
100
			'taxes'     => array(
101
				'total' => $fee->tax_data,
102
			),
103
			'order_id'  => $this->get_id(),
104
		) );
105
		$item->save();
106
		$this->add_item( $item );
107
		wc_do_deprecated_action( 'woocommerce_order_add_fee', array( $this->get_id(), $item->get_id(), $fee ), '2.7', 'Use woocommerce_new_order_item action instead.' );
108
		return $item->get_id();
109
	}
110
111
	/**
112
	 * Update a line item for the order.
113
	 *
114
	 * Note this does not update order totals.
115
	 *
116
	 * @param object|int $item order item ID or item object.
117
	 * @param WC_Product $product
118
	 * @param array $args data to update.
119
	 * @return int updated order item ID
120
	 */
121
	 public function update_product( $item, $product, $args ) {
122
		_deprecated_function( 'WC_Order::update_product', '2.7', 'Interact with WC_Order_Item_Product class' );
123
		if ( is_numeric( $item ) ) {
124
			$item = $this->get_item( $item );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
125
		}
126
		if ( ! is_object( $item ) || ! $item->is_type( 'line_item' ) ) {
127
			return false;
128
		}
129
		if ( ! $this->get_id() ) {
130
			$this->save(); // Order must exist
131
		}
132
133
		// BW compatibility with old args
134 View Code Duplication
		if ( isset( $args['totals'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
			foreach ( $args['totals'] as $key => $value ) {
136
				if ( 'tax' === $key ) {
137
					$args['total_tax'] = $value;
138
				} elseif ( 'tax_data' === $key ) {
139
					$args['taxes'] = $value;
140
				} else {
141
					$args[ $key ] = $value;
142
				}
143
			}
144
		}
145
146
		// Handly qty if set
147
		if ( isset( $args['qty'] ) ) {
148
			if ( $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
149
				$item->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ), true );
150
			}
151
			$args['subtotal'] = $args['subtotal'] ? $args['subtotal'] : $product->get_price_excluding_tax( $args['qty'] );
152
			$args['total']	= $args['total'] ? $args['total'] : $product->get_price_excluding_tax( $args['qty'] );
153
		}
154
155
		$item->set_order_id( $this->get_id() );
156
		$item->set_all( $args );
157
		$item->save();
158
		do_action( 'woocommerce_order_edit_product', $this->get_id(), $item->get_id(), $args, $product );
159
160
		return $item->get_id();
161
	}
162
163
	/**
164
	 * Update coupon for order. Note this does not update order totals.
165
	 * @param object|int $item
166
	 * @param array $args
167
	 * @return int updated order item ID
168
	 */
169
	public function update_coupon( $item, $args ) {
170
		_deprecated_function( 'WC_Order::update_coupon', '2.7', 'Interact with WC_Order_Item_Coupon class' );
171
		if ( is_numeric( $item ) ) {
172
			$item = $this->get_item( $item );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
173
		}
174
		if ( ! is_object( $item ) || ! $item->is_type( 'coupon' ) ) {
175
			return false;
176
		}
177
		if ( ! $this->get_id() ) {
178
			$this->save(); // Order must exist
179
		}
180
181
		// BW compatibility for old args
182
		if ( isset( $args['discount_amount'] ) ) {
183
			$args['discount'] = $args['discount_amount'];
184
		}
185
		if ( isset( $args['discount_amount_tax'] ) ) {
186
			$args['discount_tax'] = $args['discount_amount_tax'];
187
		}
188
189
		$item->set_order_id( $this->get_id() );
190
		$item->set_all( $args );
191
		$item->save();
192
193
		do_action( 'woocommerce_order_update_coupon', $this->get_id(), $item->get_id(), $args );
194
195
		return $item->get_id();
196
	}
197
198
	/**
199
	 * Update shipping method for order.
200
	 *
201
	 * Note this does not update the order total.
202
	 *
203
	 * @param object|int $item
204
	 * @param array $args
205
	 * @return int updated order item ID
206
	 */
207
	public function update_shipping( $item, $args ) {
208
		_deprecated_function( 'WC_Order::update_shipping', '2.7', 'Interact with WC_Order_Item_Shipping class' );
209
		if ( is_numeric( $item ) ) {
210
			$item = $this->get_item( $item );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
211
		}
212
		if ( ! is_object( $item ) || ! $item->is_type( 'shipping' ) ) {
213
			return false;
214
		}
215
		if ( ! $this->get_id() ) {
216
			$this->save(); // Order must exist
217
		}
218
219
		// BW compatibility for old args
220
		if ( isset( $args['cost'] ) ) {
221
			$args['total'] = $args['cost'];
222
		}
223
224
		$item->set_order_id( $this->get_id() );
225
		$item->set_all( $args );
226
		$item->save();
227
		$this->calculate_shipping();
228
229
		do_action( 'woocommerce_order_update_shipping', $this->get_id(), $item->get_id(), $args );
230
231
		return $item->get_id();
232
	}
233
234
	/**
235
	 * Update fee for order.
236
	 *
237
	 * Note this does not update order totals.
238
	 *
239
	 * @param object|int $item
240
	 * @param array $args
241
	 * @return int updated order item ID
242
	 */
243 View Code Duplication
	public function update_fee( $item, $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
244
		_deprecated_function( 'WC_Order::update_fee', '2.7', 'Interact with WC_Order_Item_Fee class' );
245
		if ( is_numeric( $item ) ) {
246
			$item = $this->get_item( $item );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
247
		}
248
		if ( ! is_object( $item ) || ! $item->is_type( 'fee' ) ) {
249
			return false;
250
		}
251
		if ( ! $this->get_id() ) {
252
			$this->save(); // Order must exist
253
		}
254
255
		$item->set_order_id( $this->get_id() );
256
		$item->set_all( $args );
257
		$item->save();
258
259
		do_action( 'woocommerce_order_update_fee', $this->get_id(), $item->get_id(), $args );
260
261
		return $item->get_id();
262
	}
263
264
	/**
265
	 * Update tax line on order.
266
	 * Note this does not update order totals.
267
	 *
268
	 * @since 2.7
269
	 * @param object|int $item
270
	 * @param array $args
271
	 * @return int updated order item ID
272
	 */
273 View Code Duplication
	public function update_tax( $item, $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
274
		_deprecated_function( 'WC_Order::update_tax', '2.7', 'Interact with WC_Order_Item_Tax class' );
275
		if ( is_numeric( $item ) ) {
276
			$item = $this->get_item( $item );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
277
		}
278
		if ( ! is_object( $item ) || ! $item->is_type( 'tax' ) ) {
279
			return false;
280
		}
281
		if ( ! $this->get_id() ) {
282
			$this->save(); // Order must exist
283
		}
284
285
		$item->set_order_id( $this->get_id() );
286
		$item->set_all( $args );
287
		$item->save();
288
289
		do_action( 'woocommerce_order_update_tax', $this->get_id(), $item->get_id(), $args );
290
291
		return $item->get_id();
292
	}
293
294
	/**
295
	 * Get a product (either product or variation).
296
	 * @deprecated Add deprecation notices in future release. Replaced with $item->get_product()
297
	 * @param object $item
298
	 * @return WC_Product|bool
299
	 */
300
	public function get_product_from_item( $item ) {
301
		if ( is_callable( array( $item, 'get_product' ) ) ) {
302
			$product = $item->get_product();
303
		} else {
304
			$product = false;
305
		}
306
		return apply_filters( 'woocommerce_get_product_from_item', $product, $item, $this );
307
	}
308
309
	/**
310
	 * Set the customer address.
311
	 * @param array $address Address data.
312
	 * @param string $type billing or shipping.
313
	 */
314
	public function set_address( $address, $type = 'billing' ) {
315
		foreach ( $address as $key => $value ) {
316
			update_post_meta( $this->get_id(), "_{$type}_" . $key, $value );
317
			if ( is_callable( array( $this, "set_{$type}_{$key}" ) ) ) {
318
				$this->{"set_{$type}_{$key}"}( $value );
319
			}
320
		}
321
	}
322
323
	/**
324
	 * Set an order total.
325
	 * @param float $amount
326
	 * @param string $total_type
327
	 * @return bool
328
	 */
329
	public function legacy_set_total( $amount, $total_type = 'total' ) {
330
		if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
331
			return false;
332
		}
333
334
		switch ( $total_type ) {
335
			case 'total' :
336
				$amount = wc_format_decimal( $amount, wc_get_price_decimals() );
337
				$this->set_total( $amount );
0 ignored issues
show
Bug introduced by
The method set_total() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean legacy_set_total()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
338
				update_post_meta( $this->get_id(), '_order_total', $amount );
339
				break;
340
			case 'cart_discount' :
341
				$amount = wc_format_decimal( $amount );
342
				$this->set_discount_total( $amount );
343
				update_post_meta( $this->get_id(), '_cart_discount', $amount );
344
				break;
345
			case 'cart_discount_tax' :
346
				$amount = wc_format_decimal( $amount );
347
				$this->set_discount_tax( $amount );
348
				update_post_meta( $this->get_id(), '_cart_discount_tax', $amount );
349
				break;
350
			case 'shipping' :
351
				$amount = wc_format_decimal( $amount );
352
				$this->set_shipping_total( $amount );
353
				update_post_meta( $this->get_id(), '_order_shipping', $amount );
354
				break;
355
			case 'shipping_tax' :
356
				$amount = wc_format_decimal( $amount );
357
				$this->set_shipping_tax( $amount );
358
				update_post_meta( $this->get_id(), '_order_shipping_tax', $amount );
359
				break;
360
			case 'tax' :
361
				$amount = wc_format_decimal( $amount );
362
				$this->set_cart_tax( $amount );
363
				update_post_meta( $this->get_id(), '_order_tax', $amount );
364
				break;
365
		}
366
367
		return true;
368
	}
369
370
	/**
371
	 * Magic __isset method for backwards compatibility.
372
	 * @param string $key
373
	 * @return bool
374
	 */
375
	public function __isset( $key ) {
376
		// Legacy properties which could be accessed directly in the past.
377
		$legacy_props = array( 'completed_date', 'id', 'order_type', 'post', 'status', 'post_status', 'customer_note', 'customer_message', 'user_id', 'customer_user', 'prices_include_tax', 'tax_display_cart', 'display_totals_ex_tax', 'display_cart_ex_tax', 'order_date', 'modified_date', 'cart_discount', 'cart_discount_tax', 'order_shipping', 'order_shipping_tax', 'order_total', 'order_tax', 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode', 'billing_country', 'billing_phone', 'billing_email', 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode', 'shipping_country', 'customer_ip_address', 'customer_user_agent', 'payment_method_title', 'payment_method', 'order_currency' );
378
		return $this->get_id() ? ( in_array( $key, $legacy_props ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) ) : false;
379
	}
380
381
	/**
382
	 * Magic __get method for backwards compatibility.
383
	 * @param string $key
384
	 * @return mixed
385
	 */
386
	public function __get( $key ) {
387
		_doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.7' );
388
389
		if ( 'completed_date' === $key ) {
390
			return $this->get_date_completed();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method get_date_completed() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
391
		} elseif ( 'paid_date' === $key ) {
392
			return $this->get_date_paid();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method get_date_paid() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
393
		} elseif ( 'modified_date' === $key ) {
394
			return $this->get_date_modified();
395
		} elseif ( 'order_date' === $key ) {
396
			return $this->get_date_created();
0 ignored issues
show
Bug introduced by
The method get_date_created() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean create()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
397
		} elseif ( 'id' === $key ) {
398
			return $this->get_id();
399
		} elseif ( 'post' === $key ) {
400
			return get_post( $this->get_id() );
401
		} elseif ( 'status' === $key || 'post_status' === $key ) {
402
			return $this->get_status();
403
		} elseif ( 'customer_message' === $key || 'customer_note' === $key ) {
404
			return $this->get_customer_note();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method get_customer_note() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
405
		} elseif ( in_array( $key, array( 'user_id', 'customer_user' ) ) ) {
406
			return $this->get_customer_id();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method get_customer_id() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
407
		} elseif ( 'tax_display_cart' === $key ) {
408
			return get_option( 'woocommerce_tax_display_cart' );
409
		} elseif ( 'display_totals_ex_tax' === $key ) {
410
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
411
		} elseif ( 'display_cart_ex_tax' === $key ) {
412
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
413
		} elseif ( 'cart_discount' === $key ) {
414
			return $this->get_discount();
0 ignored issues
show
Bug introduced by
The method get_discount() does not seem to exist on object<WC_Abstract_Legacy_Order>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
415
		} elseif ( 'cart_discount_tax' === $key ) {
416
			return $this->get_discount_tax();
417
		} elseif ( 'order_tax' === $key ) {
418
			return $this->get_cart_tax();
419
		} elseif ( 'order_shipping_tax' === $key ) {
420
			return $this->get_shipping_tax();
421
		} elseif ( 'order_shipping' === $key ) {
422
			return $this->get_shipping_total();
423
		} elseif ( 'order_total' === $key ) {
424
			return $this->get_total();
0 ignored issues
show
Bug introduced by
The method get_total() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_total_shipping()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
425
		} elseif ( 'order_type' === $key ) {
426
			return $this->get_type();
427
		} elseif ( 'order_currency' === $key ) {
428
			return $this->get_currency();
429
		} elseif ( 'order_version' === $key ) {
430
			return $this->get_version();
431
	 	} elseif ( is_callable( array( $this, "get_{$key}" ) ) ) {
432
			return $this->{"get_{$key}"}();
433
		} else {
434
			return get_post_meta( $this->get_id(), '_' . $key, true );
435
		}
436
	}
437
438
	/**
439
	 * has_meta function for order items.
440
	 *
441
	 * @param string $order_item_id
442
	 * @return array of meta data.
443
	 */
444
	public function has_meta( $order_item_id ) {
445
		global $wpdb;
446
447
		_deprecated_function( 'has_meta', '2.7', 'WC_Order_item::get_meta_data' );
448
449
		return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
450
			FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
451
			ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
452
	}
453
454
	/**
455
	 * Display meta data belonging to an item.
456
	 * @param  array $item
457
	 */
458
	public function display_item_meta( $item ) {
459
		_deprecated_function( 'display_item_meta', '2.7', 'wc_display_item_meta' );
460
		$product   = $item->get_product();
0 ignored issues
show
Bug introduced by
The method get_product cannot be called on $item (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
461
		$item_meta = new WC_Order_Item_Meta( $item, $product );
0 ignored issues
show
Deprecated Code introduced by
The class WC_Order_Item_Meta has been deprecated with message: 2.7.0 wc_display_item_meta function is used instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
462
		$item_meta->display();
463
	}
464
465
	/**
466
	 * Display download links for an order item.
467
	 * @param  array $item
468
	 */
469
	public function display_item_downloads( $item ) {
470
		_deprecated_function( 'display_item_downloads', '2.7', 'wc_display_item_downloads' );
471
		$product   = $item->get_product();
0 ignored issues
show
Bug introduced by
The method get_product cannot be called on $item (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
472
473
		if ( $product && $product->exists() && $product->is_downloadable() && $this->is_download_permitted() ) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method is_download_permitted() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
474
			$download_files = $this->get_item_downloads( $item );
475
			$i			  = 0;
476
			$links		  = array();
477
478
			foreach ( $download_files as $download_id => $file ) {
479
				$i++;
480
				$prefix  = count( $download_files ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
481
				$links[] = '<small class="download-url">' . $prefix . ': <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a></small>' . "\n";
482
			}
483
484
			echo '<br/>' . implode( '<br/>', $links );
485
		}
486
	}
487
488
	/**
489
	 * Get the Download URL.
490
	 *
491
	 * @param  int $product_id
492
	 * @param  int $download_id
493
	 * @return string
494
	 */
495
	public function get_download_url( $product_id, $download_id ) {
496
		_deprecated_function( 'get_download_url', '2.7', 'WC_Order_Item_Product::get_item_download_url' );
497
		return add_query_arg( array(
498
			'download_file' => $product_id,
499
			'order'         => $this->get_order_key(),
0 ignored issues
show
Bug introduced by
The method get_order_key() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_order()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
500
			'email'         => urlencode( $this->get_billing_email() ),
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Legacy_Order as the method get_billing_email() does only exist in the following sub-classes of WC_Abstract_Legacy_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
501
			'key'           => $download_id,
502
		), trailingslashit( home_url() ) );
503
	}
504
505
	/**
506
	 * Get the downloadable files for an item in this order.
507
	 *
508
	 * @param  array $item
509
	 * @return array
510
	 */
511
	public function get_item_downloads( $item ) {
512
		_deprecated_function( 'get_item_downloads', '2.7', 'WC_Order_Item_Product::get_item_downloads' );
513
		return $item->get_item_downloads();
0 ignored issues
show
Bug introduced by
The method get_item_downloads cannot be called on $item (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
514
	}
515
516
	/**
517
	 * Gets shipping total. Alias of WC_Order::get_shipping_total().
518
	 * @deprecated 2.7.0 since this is an alias only.
519
	 * @return float
520
	 */
521
	public function get_total_shipping() {
522
		return $this->get_shipping_total();
523
	}
524
525
	/**
526
	 * Get order item meta.
527
	 * @deprecated 2.7.0
528
	 * @param mixed $order_item_id
529
	 * @param string $key (default: '')
530
	 * @param bool $single (default: false)
531
	 * @return array|string
532
	 */
533
	public function get_item_meta( $order_item_id, $key = '', $single = false ) {
534
		_deprecated_function( 'get_item_meta', '2.7', 'wc_get_order_item_meta' );
535
		return get_metadata( 'order_item', $order_item_id, $key, $single );
536
	}
537
538
	/**
539
	 * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
540
	 *
541
	 * @param mixed $order_item_id
542
	 * @return array of objects
543
	 */
544
	public function get_item_meta_array( $order_item_id ) {
545
		_deprecated_function( 'get_item_meta_array', '2.7', 'WC_Order_Item::get_meta_data() (note the format has changed)' );
546
		$item            = $this->get_item( $order_item_id );
0 ignored issues
show
Bug introduced by
The method get_item() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean get_item_downloads()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
547
		$meta_data       = $item->get_meta_data();
548
		$item_meta_array = array();
549
550
		foreach ( $meta_data as $meta ) {
551
			$item_meta_array[ $meta->meta_id ] = $meta;
552
		}
553
554
		return $item_meta_array;
555
	}
556
557
	/**
558
	 * Expand item meta into the $item array.
559
	 * @deprecated 2.7.0 Item meta no longer expanded due to new order item
560
	 *		classes. This function now does nothing to avoid data breakage.
561
	 * @param array $item before expansion.
562
	 * @return array
563
	 */
564
	public function expand_item_meta( $item ) {
565
		_deprecated_function( 'expand_item_meta', '2.7', '' );
566
		return $item;
567
	}
568
569
	/**
570
	 * Load the order object. Called from the constructor.
571
	 * @deprecated 2.7.0 Logic moved to constructor
572
	 * @param int|object|WC_Order $order Order to init.
573
	 */
574
	protected function init( $order ) {
575
		_deprecated_function( 'init', '2.7', 'Logic moved to constructor' );
576
		if ( is_numeric( $order ) ) {
577
			$this->read( $order );
578
		} elseif ( $order instanceof WC_Order ) {
579
			$this->read( absint( $order->get_id() ) );
580
		} elseif ( isset( $order->ID ) ) {
581
			$this->read( absint( $order->ID ) );
582
		}
583
	}
584
585
	/**
586
	 * Gets an order from the database.
587
	 * @deprecated 2.7
588
	 * @param int $id (default: 0).
589
	 * @return bool
590
	 */
591 View Code Duplication
	public function get_order( $id = 0 ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
592
		_deprecated_function( 'get_order', '2.7', 'read' );
593
		if ( ! $id ) {
594
			return false;
595
		}
596
		if ( $result = get_post( $id ) ) {
597
			$this->populate( $result );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Abstract_Legacy_Order::populate() has been deprecated with message: 2.7

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
598
			return true;
599
		}
600
		return false;
601
	}
602
603
	/**
604
	 * Populates an order from the loaded post data.
605
	 * @deprecated 2.7
606
	 * @param mixed $result
607
	 */
608
	public function populate( $result ) {
609
		_deprecated_function( 'populate', '2.7', 'read' );
610
		$this->read( $result->ID );
611
	}
612
613
	/**
614
	 * Cancel the order and restore the cart (before payment).
615
	 * @deprecated 2.7.0 Moved to event handler.
616
	 * @param string $note (default: '') Optional note to add.
617
	 */
618
	public function cancel_order( $note = '' ) {
619
		_deprecated_function( 'cancel_order', '2.7', 'update_status' );
620
		WC()->session->set( 'order_awaiting_payment', false );
621
		$this->update_status( 'cancelled', $note );
0 ignored issues
show
Bug introduced by
The method update_status() does not exist on WC_Abstract_Legacy_Order. Did you maybe mean update()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
622
	}
623
624
	/**
625
	 * Record sales.
626
	 * @deprecated 2.7.0
627
	 */
628
	public function record_product_sales() {
629
		_deprecated_function( 'record_product_sales', '2.7', 'wc_update_total_sales_counts' );
630
		wc_update_total_sales_counts( $this->get_id() );
631
	}
632
633
	/**
634
	 * Increase applied coupon counts.
635
	 * @deprecated 2.7.0
636
	 */
637
	public function increase_coupon_usage_counts() {
638
		_deprecated_function( 'increase_coupon_usage_counts', '2.7', 'wc_update_coupon_usage_counts' );
639
		wc_update_coupon_usage_counts( $this->get_id() );
640
	}
641
642
	/**
643
	 * Decrease applied coupon counts.
644
	 * @deprecated 2.7.0
645
	 */
646
	public function decrease_coupon_usage_counts() {
647
		_deprecated_function( 'decrease_coupon_usage_counts', '2.7', 'wc_update_coupon_usage_counts' );
648
		wc_update_coupon_usage_counts( $this->get_id() );
649
	}
650
651
	/**
652
	 * Reduce stock levels for all line items in the order.
653
	 * @deprecated 2.7.0
654
	 */
655
	public function reduce_order_stock() {
656
		_deprecated_function( 'reduce_order_stock', '2.7', 'wc_reduce_stock_levels' );
657
		wc_reduce_stock_levels( $this->get_id() );
658
	}
659
660
	/**
661
	 * Send the stock notifications.
662
	 * @deprecated 2.7.0 No longer needs to be called directly.
663
	 */
664
	public function send_stock_notifications( $product, $new_stock, $qty_ordered ) {
0 ignored issues
show
Unused Code introduced by
The parameter $product is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $new_stock is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $qty_ordered is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
665
		_deprecated_function( 'send_stock_notifications', '2.7' );
666
	}
667
668
	/**
669
	 * Output items for display in html emails.
670
	 * @deprecated 2.7.0 Moved to template functions.
671
	 * @param array $args Items args.
672
	 * @return string
673
	 */
674
	public function email_order_items_table( $args = array() ) {
675
		_deprecated_function( 'email_order_items_table', '2.7', 'wc_get_email_order_items' );
676
		return wc_get_email_order_items( $this, $args );
0 ignored issues
show
Compatibility introduced by
$this of type object<WC_Abstract_Legacy_Order> is not a sub-type of object<WC_Order>. It seems like you assume a child class of the class WC_Abstract_Legacy_Order to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
677
	}
678
679
	/**
680
	 * Get currency.
681
	 * @deprecated 2.7.0
682
	 */
683
	public function get_order_currency() {
684
		_deprecated_function( 'get_order_currency', '2.7', 'get_currency' );
685
		return apply_filters( 'woocommerce_get_order_currency', $this->get_currency(), $this );
686
	}
687
}
688