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 DebtorItem 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 DebtorItem, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class DebtorItem extends Intraface_Standard |
||
18 | { |
||
19 | /** |
||
20 | * @var array |
||
21 | */ |
||
22 | public $value; |
||
23 | |||
24 | /** |
||
25 | * @var integer |
||
26 | */ |
||
27 | private $id; |
||
28 | |||
29 | /** |
||
30 | * @var object |
||
31 | */ |
||
32 | private $invoice; |
||
|
|||
33 | |||
34 | /** |
||
35 | * @var object |
||
36 | */ |
||
37 | private $db; |
||
38 | |||
39 | /** |
||
40 | * @var object |
||
41 | */ |
||
42 | private $product; |
||
43 | |||
44 | /** |
||
45 | * @var object Intraface_modules_product_Variation |
||
46 | */ |
||
47 | private $product_variation; |
||
48 | |||
49 | /** |
||
50 | * @var object Intraface_modules_product_Variation_Detail |
||
51 | */ |
||
52 | private $product_variation_detail; |
||
53 | |||
54 | /** |
||
55 | * @var integer |
||
56 | */ |
||
57 | private $product_id; |
||
58 | |||
59 | /** |
||
60 | * @var object |
||
61 | */ |
||
62 | public $error; |
||
63 | |||
64 | /** |
||
65 | * Constructor |
||
66 | * |
||
67 | * @param object $debtor Debtor object |
||
68 | * @param integer $id If a special item id is needed |
||
69 | * |
||
70 | * @return void |
||
71 | */ |
||
72 | 68 | View Code Duplication | public function __construct($debtor, $id = 0) |
83 | |||
84 | /** |
||
85 | * Loads data |
||
86 | * |
||
87 | * @return void |
||
88 | */ |
||
89 | 1 | private function load() |
|
105 | |||
106 | /** |
||
107 | * returns product object with loaded from item |
||
108 | * |
||
109 | * @return object Product |
||
110 | */ |
||
111 | View Code Duplication | private function getProduct() |
|
121 | |||
122 | /** |
||
123 | * Returns Product variation loaded from item |
||
124 | * |
||
125 | * @return object Intraface_modules_product_Variation |
||
126 | */ |
||
127 | View Code Duplication | private function getProductVariation() |
|
140 | |||
141 | /** |
||
142 | * Returns product variation detail loaded from item |
||
143 | * |
||
144 | * @return object Intraface_modules_product_Variation_Detail |
||
145 | */ |
||
146 | View Code Duplication | private function getProductVariationDetail() |
|
159 | |||
160 | /** |
||
161 | * Returns price of product without vat |
||
162 | * |
||
163 | * @return float price of product |
||
164 | */ |
||
165 | View Code Duplication | public function getProductPrice() |
|
173 | |||
174 | /** |
||
175 | * Returns weight of product without vat |
||
176 | * |
||
177 | * @return integer weight of product |
||
178 | */ |
||
179 | public function getProductWeight() |
||
187 | |||
188 | /** |
||
189 | * Returns number of product |
||
190 | * |
||
191 | * @return string product number |
||
192 | */ |
||
193 | View Code Duplication | public function getProductNumber() |
|
201 | |||
202 | /** |
||
203 | * Returns name of product |
||
204 | * |
||
205 | * @return string name of product |
||
206 | */ |
||
207 | View Code Duplication | public function getProductName() |
|
215 | |||
216 | |||
217 | /** |
||
218 | * Gets price without taxes |
||
219 | * |
||
220 | * @return float |
||
221 | */ |
||
222 | public function getPrice() |
||
229 | |||
230 | /** |
||
231 | * Gets weight |
||
232 | * |
||
233 | * @return float |
||
234 | */ |
||
235 | public function getWeight() |
||
239 | |||
240 | /** |
||
241 | * Gets the tax percent on the individual product |
||
242 | * |
||
243 | * @return float |
||
244 | */ |
||
245 | public function getTaxPercent() |
||
253 | |||
254 | /** |
||
255 | * Saves data |
||
256 | * |
||
257 | * @TODO: Should have product object instead of product id in the param array. |
||
258 | * |
||
259 | * @param array $input Values to save |
||
260 | * |
||
261 | * @return integer |
||
262 | */ |
||
263 | 19 | public function save($input) |
|
358 | |||
359 | /** |
||
360 | * Changes the product assigned to the item |
||
361 | * |
||
362 | * @param integer $product_id |
||
363 | * @param integer $product_variation_id |
||
364 | * @return boolean true on success |
||
365 | */ |
||
366 | public function changeProduct($product_id, $product_variation_id = 0) |
||
407 | |||
408 | /** |
||
409 | * Deletes a product |
||
410 | * |
||
411 | * @return boolean |
||
412 | */ |
||
413 | public function delete() |
||
429 | |||
430 | /** |
||
431 | * Get a list with Debtor items |
||
432 | * |
||
433 | * @return array |
||
434 | */ |
||
435 | 63 | public function getList() |
|
436 | { |
||
437 | 63 | $db = new DB_Sql; |
|
438 | 63 | $db2 = new DB_Sql; |
|
439 | |||
440 | 63 | $db->query("SELECT id, product_id, product_detail_id, product_variation_id, product_variation_detail_id, quantity, description FROM debtor_item WHERE active = 1 AND intranet_id = ".$this->debtor->kernel->intranet->get("id")." AND debtor_id = ".$this->debtor->get("id")." ORDER BY position ASC, id ASC"); |
|
441 | 63 | $i = 0; |
|
442 | 63 | $j = 0; |
|
443 | 63 | $item_no_vat = array(); |
|
444 | 63 | $item_with_vat = array(); |
|
445 | |||
446 | 63 | require_once 'Intraface/modules/product/Product.php'; |
|
447 | |||
448 | 63 | $currency = $this->debtor->getCurrency(); |
|
449 | |||
450 | 63 | while ($db->nextRecord()) { |
|
451 | 15 | $product = new Product($this->debtor->kernel, $db->f('product_id'), $db->f('product_detail_id')); |
|
452 | |||
453 | 15 | if ($product->getId() != 0 && $product->get('detail_id') != 0) { |
|
454 | 15 | $item = array(); |
|
455 | 15 | $item["description"] = $db->f("description"); |
|
456 | 15 | $item["quantity"] = $db->f("quantity"); |
|
457 | 15 | $item["id"] = $db->f("id"); |
|
458 | |||
459 | 15 | $item["vat"] = $product->get("vat"); |
|
460 | 15 | $item["product_id"] = $product->getId(); |
|
461 | 15 | $item["product_detail_id"] = $product->get("detail_id"); |
|
462 | 15 | $unit = $product->get('unit'); |
|
463 | 15 | View Code Duplication | if ($db->f("quantity") == 1) { |
464 | $item["unit"] = $unit['singular']; |
||
465 | } else { |
||
466 | 15 | $item["unit"] = $unit['plural']; |
|
467 | } |
||
468 | |||
469 | 15 | if ($product->get('has_variation')) { |
|
470 | $variation = $product->getVariation($db->f('product_variation_id')); |
||
471 | $detail = $variation->getDetail($db->f('product_variation_detail_id')); |
||
472 | $item["name"] = $product->get("name").' - '.$variation->getName(); |
||
473 | $item["number"]= $product->get("number").'.'.$variation->getNumber(); |
||
474 | $item["price"] = $detail->getPrice($product); |
||
475 | if ($currency) { |
||
476 | $item['price_currency'] = $detail->getPriceInCurrency($currency, $this->debtor->get('currency_product_price_exchange_rate_id'), $product); |
||
477 | } |
||
478 | } else { |
||
479 | 15 | $item["name"] = $product->get("name"); |
|
480 | 15 | $item["number"]= $product->get("number"); |
|
481 | 15 | $item["price"] = $product->getDetails()->getPrice(); |
|
482 | 15 | if ($currency) { |
|
483 | 2 | $item['price_currency'] = $product->getDetails()->getPriceInCurrency($currency, $this->debtor->get('currency_product_price_exchange_rate_id')); |
|
484 | 18 | } |
|
485 | } |
||
486 | |||
487 | 15 | if ($product->get("vat") == 0) { |
|
488 | 2 | $item_no_vat[$j] = $item; |
|
489 | 2 | $item_no_vat[$j]["amount"] = new Ilib_Variable_Float($item["quantity"] * $item["price"]->getAsIso(2)); |
|
490 | 2 | View Code Duplication | if ($currency) { |
491 | 18 | $item_no_vat[$j]["amount_currency"] = new Ilib_Variable_Float($item["quantity"] * $item["price_currency"]->getAsIso(2), 'iso'); |
|
492 | } |
||
493 | 2 | $j++; |
|
494 | 2 | } else { |
|
495 | 13 | $item_with_vat[$i] = $item; |
|
496 | 13 | $item_with_vat[$i]["amount"] = new Ilib_Variable_Float($item["quantity"] * $item["price"]->getAsIso(2) * 1.25); |
|
497 | 13 | View Code Duplication | if ($currency) { |
498 | 2 | $item_with_vat[$i]["amount_currency"] = new Ilib_Variable_Float($item["quantity"] * $item["price_currency"]->getAsIso(2) * 1.25, 'iso'); |
|
499 | 2 | } |
|
500 | 13 | $i++; |
|
501 | } |
||
502 | 15 | } else { |
|
503 | throw new Exception("Ugyldig produktdetalje i DebtorItem->getList() on ".$db->f('product_id').'/'.$db->f('product_detail_id')); |
||
504 | } |
||
505 | 15 | } |
|
506 | 63 | unset($db); |
|
507 | 63 | return(array_merge($item_with_vat, $item_no_vat)); |
|
508 | } |
||
509 | |||
510 | /** |
||
511 | * Method to get quantity of each product |
||
512 | * |
||
513 | * TODO This should not be in this class |
||
514 | * |
||
515 | * @param integer $product_id Product id |
||
516 | * @param string $from_date Which date to start the quantity from |
||
517 | * @param string $sent TODO WHAT IS THIS |
||
518 | * |
||
519 | * @return integer |
||
520 | */ |
||
521 | 1 | public function getQuantity($product_id, $product_variation_id, $from_date, $sent = "") |
|
568 | |||
569 | /** |
||
570 | * Returns position object |
||
571 | * |
||
572 | * @return object Ilib_Position |
||
573 | */ |
||
574 | 18 | function getPosition($db) |
|
578 | } |
||
579 |
This check marks private properties in classes that are never used. Those properties can be removed.