Complex classes like CartController 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 CartController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class CartController extends Controller |
||
34 | { |
||
35 | public function behaviors() |
||
36 | { |
||
37 | return [ |
||
38 | [ |
||
39 | 'class' => DisableRobotIndexBehavior::className(), |
||
40 | ] |
||
41 | ]; |
||
42 | } |
||
43 | |||
44 | /** |
||
45 | * Get Order. |
||
46 | * @param bool $create Create order if it does not exist |
||
47 | * @param bool $throwException Throw exception if it does not exist |
||
48 | * @return null|Order |
||
49 | * @throws NotFoundHttpException |
||
50 | */ |
||
51 | protected function loadOrder($create = false, $throwException = true) |
||
52 | { |
||
53 | $model = Order::getOrder($create); |
||
54 | if (is_null($model) && $throwException) { |
||
55 | throw new NotFoundHttpException; |
||
56 | } |
||
57 | return $model; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Get OrderItem. |
||
62 | * @param int $id |
||
63 | * @param bool $checkOrderAttachment |
||
64 | * @return OrderItem |
||
|
|||
65 | * @throws NotFoundHttpException |
||
66 | */ |
||
67 | protected function loadOrderItem($id, $checkOrderAttachment = true) |
||
68 | { |
||
69 | /** @var OrderItem $orderItemModel */ |
||
70 | $orderModel = $checkOrderAttachment ? $this->loadOrder() : null; |
||
71 | $orderItemModel = OrderItem::findOne($id); |
||
72 | if (is_null($orderItemModel) |
||
73 | || ($checkOrderAttachment && (is_null($orderModel) || $orderItemModel->order_id != $orderModel->id)) |
||
74 | ) { |
||
75 | throw new NotFoundHttpException; |
||
76 | } |
||
77 | return $orderItemModel; |
||
78 | } |
||
79 | |||
80 | protected function addProductsToOrder($products, $parentId = 0) |
||
81 | { |
||
82 | if (!is_array($products)) { |
||
83 | throw new BadRequestHttpException; |
||
84 | } |
||
85 | $order = $this->loadOrder(true); |
||
86 | $result = [ |
||
87 | 'errors' => [], |
||
88 | 'itemModalPreview' => '', |
||
89 | ]; |
||
90 | foreach ($products as $product) { |
||
91 | if (!isset($product['id']) || is_null($productModel = Product::findById($product['id']))) { |
||
92 | $result['errors'][] = Yii::t('app', 'Product not found.'); |
||
93 | continue; |
||
94 | } |
||
95 | /** @var Product $productModel */ |
||
96 | $quantity = isset($product['quantity']) && (double) $product['quantity'] > 0 |
||
97 | ? (double) $product['quantity'] |
||
98 | : 1; |
||
99 | $quantity = $productModel->measure->ceilQuantity($quantity); |
||
100 | if ($this->module->allowToAddSameProduct |
||
101 | || is_null($orderItem = OrderItem::findOne(['order_id' => $order->id, 'product_id' => $productModel->id, 'parent_id' => 0])) |
||
102 | ) { |
||
103 | $orderItem = new OrderItem; |
||
104 | $orderItem->attributes = [ |
||
105 | 'parent_id' => $parentId, |
||
106 | 'order_id' => $order->id, |
||
107 | 'product_id' => $productModel->id, |
||
108 | 'quantity' => $quantity, |
||
109 | 'price_per_pcs' => PriceHelper::getProductPrice( |
||
110 | $productModel, |
||
111 | $order, |
||
112 | 1, |
||
113 | SpecialPriceList::TYPE_CORE |
||
114 | ), |
||
115 | ]; |
||
116 | } else { |
||
117 | /** @var OrderItem $orderItem */ |
||
118 | $orderItem->quantity += $quantity; |
||
119 | } |
||
120 | if (!$orderItem->save()) { |
||
121 | $result['errors'][] = Yii::t('app', 'Cannot save order item.'); |
||
122 | } else { |
||
123 | // refresh order |
||
124 | Order::clearStaticOrder(); |
||
125 | $order = $this->loadOrder(false); |
||
126 | } |
||
127 | if (isset($product['children'])) { |
||
128 | $result = ArrayHelper::merge( |
||
129 | $result, |
||
130 | $this->addProductsToOrder($product['children'], $orderItem->id) |
||
131 | ); |
||
132 | } |
||
133 | if ($parentId === 0) { |
||
134 | $result['itemModalPreview'] .= $this->renderPartial( |
||
135 | 'item-modal-preview', |
||
136 | [ |
||
137 | 'order' => $order, |
||
138 | 'orderItem' => $orderItem, |
||
139 | 'product' => $product, |
||
140 | ] |
||
141 | ); |
||
142 | } |
||
143 | } |
||
144 | if ($parentId === 0) { |
||
145 | $order->calculate(true); |
||
146 | } |
||
147 | $mainCurrency = Currency::getMainCurrency(); |
||
148 | return ArrayHelper::merge( |
||
149 | $result, |
||
150 | [ |
||
151 | 'itemsCount' => $order->items_count, |
||
152 | 'success' => true, // @todo Return true success value |
||
153 | 'totalPrice' => $mainCurrency->format($order->total_price), |
||
154 | ] |
||
155 | ); |
||
156 | } |
||
157 | |||
158 | public function actionAdd() |
||
170 | |||
171 | public function actionChangeQuantity() |
||
172 | { |
||
173 | Yii::$app->response->format = Response::FORMAT_JSON; |
||
174 | $id = Yii::$app->request->post('id'); |
||
211 | |||
212 | /** |
||
213 | * Delete OrderItem action. |
||
214 | * @param int $id |
||
215 | * @throws NotFoundHttpException |
||
216 | * @throws \Exception |
||
217 | * @return array |
||
218 | */ |
||
219 | public function actionDelete($id) |
||
247 | |||
248 | public function actionClear() |
||
258 | |||
259 | public function actionIndex() |
||
288 | |||
289 | /** |
||
290 | * @return string|Response |
||
291 | * @throws NotFoundHttpException |
||
292 | */ |
||
293 | public function actionStage() |
||
341 | |||
342 | /** |
||
343 | * @param null $id |
||
344 | * @return Response |
||
345 | * @throws NotFoundHttpException |
||
346 | * @throws \yii\base\Exception |
||
347 | */ |
||
348 | public function actionStageLeaf($id = null) |
||
392 | } |
||
393 |
This check compares the return type specified in the
@return
annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.If the return type contains the type array, this check recommends the use of a more specific type like
String[]
orarray<String>
.