Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WC_Legacy_Cart often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WC_Legacy_Cart, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | abstract class WC_Legacy_Cart { |
||
19 | /** |
||
20 | * Handle unset props. |
||
21 | * @param string $key |
||
22 | * @return mixed |
||
23 | */ |
||
24 | public function __get( $key ) { |
||
103 | |||
104 | /** |
||
105 | * @deprecated 2.7.0 |
||
106 | */ |
||
107 | public function add_discount( $coupon_code ) { |
||
111 | |||
112 | /** |
||
113 | * @deprecated 2.7.0 |
||
114 | */ |
||
115 | public function has_discount( $coupon_code = '' ) { |
||
119 | |||
120 | /** |
||
121 | * @deprecated 2.7.0 |
||
122 | */ |
||
123 | public function get_applied_coupons() { |
||
127 | |||
128 | /** |
||
129 | * @deprecated 2.7.0 |
||
130 | */ |
||
131 | public function check_cart_coupons() { |
||
135 | |||
136 | /** |
||
137 | * @deprecated 2.7.0 |
||
138 | */ |
||
139 | public function check_customer_coupons( $posted ) { |
||
144 | |||
145 | /** |
||
146 | * @deprecated 2.7.0 |
||
147 | */ |
||
148 | public function show_shipping() { |
||
152 | |||
153 | /** |
||
154 | * @deprecated 2.7.0 |
||
155 | */ |
||
156 | public function calculate_fees() { |
||
160 | |||
161 | /** |
||
162 | * Add a product to the cart. |
||
163 | * @deprecated 2.7.0 |
||
164 | * @param int $product_id contains the id of the product to add to the cart |
||
165 | * @param int $quantity contains the quantity of the item to add |
||
166 | * @param int $variation_id |
||
167 | * @param array $variation attribute values |
||
168 | * @param array $cart_item_data extra cart item data we want to pass into the item |
||
169 | * @return string|bool $cart_item_key |
||
170 | */ |
||
171 | public function add_to_cart( $product_id = 0, $quantity = 1, $variation_id = 0, $variation = array(), $cart_item_data = array() ) { |
||
185 | |||
186 | /** |
||
187 | * Get cart items quantities - merged so we can do accurate stock checks on items across multiple lines. |
||
188 | * @return array |
||
189 | */ |
||
190 | public function get_cart_item_quantities() { |
||
194 | |||
195 | /** |
||
196 | * @deprecated 2.7.0 |
||
197 | */ |
||
198 | public function check_cart_items() { |
||
202 | |||
203 | /** |
||
204 | * @deprecated 2.7.0 |
||
205 | */ |
||
206 | public function check_cart_item_stock() { |
||
209 | |||
210 | /** |
||
211 | * @deprecated 2.7.0 |
||
212 | */ |
||
213 | public function persistent_cart_update() { |
||
216 | |||
217 | /** |
||
218 | * @deprecated 2.7.0 |
||
219 | */ |
||
220 | public function persistent_cart_destroy() { |
||
223 | |||
224 | /** |
||
225 | * Determines the value that the customer spent and the subtotal |
||
226 | * displayed, used for things like coupon validation. |
||
227 | * |
||
228 | * Since the coupon lines are displayed based on the TAX DISPLAY value |
||
229 | * of cart, this is used to determine the spend. |
||
230 | * |
||
231 | * If cart totals are shown including tax, use the subtotal. |
||
232 | * If cart totals are shown excluding tax, use the subtotal ex tax |
||
233 | * (tax is shown after coupons). |
||
234 | * @deprecated 2.7.0 |
||
235 | * @since 2.6.0 |
||
236 | * @return string |
||
237 | */ |
||
238 | public function get_displayed_subtotal() { |
||
242 | |||
243 | /** |
||
244 | * Get the product row price per item. |
||
245 | * |
||
246 | * @param WC_Product $product |
||
247 | * @return string formatted price |
||
248 | */ |
||
249 | public function get_product_price( $product ) { |
||
253 | |||
254 | /** |
||
255 | * Gets the sub total (after calculation). |
||
256 | * @deprecated 2.7.0 |
||
257 | * @param bool $compound whether to include compound taxes |
||
258 | * @return string formatted price |
||
259 | */ |
||
260 | public function get_cart_subtotal( $compound = false ) { |
||
264 | |||
265 | /** |
||
266 | * Get the product row subtotal. |
||
267 | * |
||
268 | * Gets the tax etc to avoid rounding issues. |
||
269 | * |
||
270 | * When on the checkout (review order), this will get the subtotal based on the customer's tax rate rather than the base rate. |
||
271 | * |
||
272 | * @param WC_Product $product |
||
273 | * @param int $quantity |
||
274 | * @return string formatted price |
||
275 | */ |
||
276 | public function get_product_subtotal( $product, $quantity ) { |
||
280 | |||
281 | /** |
||
282 | * Gets the total discount amount. |
||
283 | * @deprecated 2.7.0 in favor to get_cart_discount_total() |
||
284 | */ |
||
285 | public function get_total_discount() { |
||
289 | |||
290 | /** |
||
291 | * Gets the url to the cart page. |
||
292 | * |
||
293 | * @deprecated 2.5.0 in favor to wc_get_cart_url() |
||
294 | * @return string url to page |
||
295 | */ |
||
296 | public function get_cart_url() { |
||
300 | |||
301 | /** |
||
302 | * Gets the url to the checkout page. |
||
303 | * |
||
304 | * @deprecated 2.5.0 in favor to wc_get_checkout_url() |
||
305 | * @return string url to page |
||
306 | */ |
||
307 | public function get_checkout_url() { |
||
311 | |||
312 | /** |
||
313 | * Coupons enabled function. Filterable. |
||
314 | * |
||
315 | * @deprecated 2.5.0 in favor to wc_coupons_enabled() |
||
316 | * @return bool |
||
317 | */ |
||
318 | public function coupons_enabled() { |
||
322 | |||
323 | /** |
||
324 | * Sees if we need a shipping address. |
||
325 | * |
||
326 | * @deprecated 2.5.0 in favor to wc_ship_to_billing_address_only() |
||
327 | * @return bool |
||
328 | */ |
||
329 | public function ship_to_billing_address_only() { |
||
333 | |||
334 | /** |
||
335 | * @deprecated 2.7.0 |
||
336 | */ |
||
337 | public function get_cross_sells() { |
||
341 | |||
342 | /** |
||
343 | * @deprecated 2.7.0 |
||
344 | */ |
||
345 | public function get_remove_url( $cart_item_key ) { |
||
349 | |||
350 | /** |
||
351 | * @deprecated 2.7.0 |
||
352 | */ |
||
353 | public function get_undo_url( $cart_item_key ) { |
||
357 | |||
358 | /** |
||
359 | * @deprecated 2.7.0 |
||
360 | */ |
||
361 | public function get_discounted_price( $values, $price, $add_totals = false ) { |
||
365 | |||
366 | /** |
||
367 | * @deprecated 2.7.0 |
||
368 | */ |
||
369 | public function get_item_data( $cart_item, $flat = false ) { |
||
373 | |||
374 | /** |
||
375 | * @deprecated 2.7.0 Unused method. |
||
376 | */ |
||
377 | public function get_total_ex_tax() { |
||
381 | |||
382 | /** |
||
383 | * @deprecated 2.7.0 Unused method. |
||
384 | */ |
||
385 | public function init() { |
||
388 | |||
389 | /** |
||
390 | * @deprecated 2.7.0 Taxes are just not calculated when not needed, so no need to remove them. |
||
391 | */ |
||
392 | public function remove_taxes() { |
||
395 | |||
396 | /** |
||
397 | * @deprecated 2.7.0 |
||
398 | */ |
||
399 | public function find_product_in_cart( $cart_id = false ) { |
||
408 | |||
409 | /** |
||
410 | * Generate a unique ID for the cart item being added. |
||
411 | * @deprecated 2.7.0 |
||
412 | * @param int $product_id - id of the product the key is being generated for |
||
413 | * @param int $variation_id of the product the key is being generated for |
||
414 | * @param array $variation data for the cart item |
||
415 | * @param array $cart_item_data other cart item data passed which affects this items uniqueness in the cart |
||
416 | * @return string cart item key |
||
417 | */ |
||
418 | public function generate_cart_id( $product_id, $variation_id = 0, $variation = array(), $cart_item_data = array() ) { |
||
422 | |||
423 | /** |
||
424 | * @deprecated 2.7.0 |
||
425 | */ |
||
426 | public function check_cart_item_validity() { |
||
430 | |||
431 | /** |
||
432 | * @deprecated 2.7.0 Unused |
||
433 | */ |
||
434 | public function get_cart_shipping_total() { |
||
467 | |||
468 | /** |
||
469 | * @deprecated 2.7.0 Unused |
||
470 | */ |
||
471 | public function get_tax_amount( $tax_rate_id ) { |
||
476 | |||
477 | /** |
||
478 | * @deprecated 2.7.0 Unused |
||
479 | */ |
||
480 | public function get_shipping_tax_amount( $tax_rate_id ) { |
||
485 | |||
486 | /** |
||
487 | * @deprecated 2.7.0 Unused |
||
488 | */ |
||
489 | public function get_cart_total() { |
||
498 | |||
499 | /** |
||
500 | * @deprecated 2.7.0 Unused |
||
501 | */ |
||
502 | public function get_cart_tax() { |
||
507 | } |
||
508 |
Let’s take a look at an example:
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
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: