ShowPage   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 553
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
wmc 63
lcom 2
cbo 3
dl 0
loc 553
rs 3.36
c 0
b 0
f 0

54 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A hasCustomer() 0 6 1
A hasShippingAddress() 0 6 1
A hasBillingAddress() 0 6 1
A hasShipment() 0 6 1
A specifyTrackingCode() 0 4 1
A canShipOrder() 0 4 1
A shipOrder() 0 4 1
A hasPayment() 0 6 1
A canCompleteOrderLastPayment() 0 4 1
A completeOrderLastPayment() 0 4 1
A refundOrderLastPayment() 0 4 1
A countItems() 0 4 1
A isProductInTheList() 0 22 5
A getItemsTotal() 0 6 1
A getTotal() 0 6 1
A getShippingTotal() 0 6 1
A getTaxTotal() 0 6 1
A hasShippingCharge() 0 6 1
A getPromotionTotal() 0 6 1
A hasPromotionDiscount() 0 6 1
A hasShippingPromotion() 0 4 1
A hasTax() 0 6 1
A getItemCode() 0 4 1
A getItemUnitPrice() 0 4 1
A getItemDiscountedUnitPrice() 0 4 1
A getItemQuantity() 0 4 1
A getItemSubtotal() 0 4 1
A getItemDiscount() 0 4 1
A getItemTax() 0 4 1
A getItemTotal() 0 4 1
A getPaymentAmount() 0 6 1
A getPaymentsCount() 0 10 2
A getShipmentsCount() 0 10 2
A hasCancelButton() 0 4 1
A getOrderState() 0 4 1
A getPaymentState() 0 4 1
A getShippingState() 0 4 1
A cancelOrder() 0 4 1
A deleteOrder() 0 4 1
A hasNote() 0 6 1
A hasShippingProvinceName() 0 6 1
A hasBillingProvinceName() 0 6 1
A getIpAddressAssigned() 0 4 1
A getOrderCurrency() 0 4 1
A hasRefundButton() 0 4 1
A getShippingPromotionData() 0 4 1
A getRouteName() 0 4 1
A getDefinedElements() 0 26 1
A getTableAccessor() 0 4 1
A hasAddress() 0 9 4
A getItemProperty() 0 9 1
A getLastOrderPaymentElement() 0 9 1
A getLastOrderShipmentElement() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like ShowPage 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 ShowPage, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Behat\Page\Admin\Order;
15
16
use Behat\Mink\Element\NodeElement;
17
use Behat\Mink\Exception\ElementNotFoundException;
18
use Behat\Mink\Session;
19
use Sylius\Behat\Page\SymfonyPage;
20
use Sylius\Behat\Service\Accessor\TableAccessorInterface;
21
use Sylius\Component\Core\Model\OrderInterface;
22
use Symfony\Component\Routing\RouterInterface;
23
24
class ShowPage extends SymfonyPage implements ShowPageInterface
25
{
26
    /**
27
     * @var TableAccessorInterface
28
     */
29
    private $tableAccessor;
30
31
    /**
32
     * @param Session $session
33
     * @param array $parameters
34
     * @param RouterInterface $router
35
     * @param TableAccessorInterface $tableAccessor
36
     */
37
    public function __construct(
38
        Session $session,
39
        array $parameters,
40
        RouterInterface $router,
41
        TableAccessorInterface $tableAccessor
42
    ) {
43
        parent::__construct($session, $parameters, $router);
44
45
        $this->tableAccessor = $tableAccessor;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function hasCustomer($customerName)
52
    {
53
        $customerText = $this->getElement('customer')->getText();
54
55
        return stripos($customerText, $customerName) !== false;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function hasShippingAddress($customerName, $street, $postcode, $city, $countryName)
62
    {
63
        $shippingAddressText = $this->getElement('shipping_address')->getText();
64
65
        return $this->hasAddress($shippingAddressText, $customerName, $street, $postcode, $city, $countryName);
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function hasBillingAddress($customerName, $street, $postcode, $city, $countryName)
72
    {
73
        $billingAddressText = $this->getElement('billing_address')->getText();
74
75
        return $this->hasAddress($billingAddressText, $customerName, $street, $postcode, $city, $countryName);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function hasShipment($shippingDetails)
82
    {
83
        $shipmentsText = $this->getElement('shipments')->getText();
84
85
        return stripos($shipmentsText, $shippingDetails) !== false;
86
    }
87
88
    public function specifyTrackingCode($code)
89
    {
90
        $this->getDocument()->fillField('sylius_shipment_ship_tracking', $code);
91
    }
92
93
    public function canShipOrder(OrderInterface $order)
94
    {
95
        return $this->getLastOrderShipmentElement($order)->hasButton('Ship');
96
    }
97
98
    public function shipOrder(OrderInterface $order)
99
    {
100
        $this->getLastOrderShipmentElement($order)->pressButton('Ship');
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function hasPayment($paymentDetails)
107
    {
108
        $paymentsText = $this->getElement('payments')->getText();
109
110
        return stripos($paymentsText, $paymentDetails) !== false;
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function canCompleteOrderLastPayment(OrderInterface $order)
117
    {
118
        return $this->getLastOrderPaymentElement($order)->hasButton('Complete');
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function completeOrderLastPayment(OrderInterface $order)
125
    {
126
        $this->getLastOrderPaymentElement($order)->pressButton('Complete');
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function refundOrderLastPayment(OrderInterface $order)
133
    {
134
        $this->getLastOrderPaymentElement($order)->pressButton('Refund');
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function countItems()
141
    {
142
        return $this->tableAccessor->countTableBodyRows($this->getElement('table'));
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function isProductInTheList(string $productName): bool
149
    {
150
        try {
151
            $table = $this->getElement('table');
152
            $rows = $this->tableAccessor->getRowsWithFields(
153
                $table,
154
                ['item' => $productName]
155
            );
156
157
            foreach ($rows as $row) {
158
                $field = $this->tableAccessor->getFieldFromRow($table, $row, 'item');
159
                $name = $field->find('css', '.sylius-product-name');
160
                if (null !== $name && $name->getText() === $productName) {
161
                    return true;
162
                }
163
            }
164
165
            return false;
166
        } catch (\InvalidArgumentException $exception) {
167
            return false;
168
        }
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function getItemsTotal()
175
    {
176
        $itemsTotalElement = $this->getElement('items_total');
177
178
        return trim(str_replace('Subtotal:', '', $itemsTotalElement->getText()));
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function getTotal()
185
    {
186
        $totalElement = $this->getElement('total');
187
188
        return trim(str_replace('Total:', '', $totalElement->getText()));
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194
    public function getShippingTotal()
195
    {
196
        $shippingTotalElement = $this->getElement('shipping_total');
197
198
        return trim(str_replace('Shipping total:', '', $shippingTotalElement->getText()));
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    public function getTaxTotal()
205
    {
206
        $taxTotalElement = $this->getElement('tax_total');
207
208
        return trim(str_replace('Tax total:', '', $taxTotalElement->getText()));
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function hasShippingCharge($shippingCharge)
215
    {
216
        $shippingChargesText = $this->getElement('shipping_charges')->getText();
217
218
        return stripos($shippingChargesText, $shippingCharge) !== false;
219
    }
220
221
    /**
222
     * {@inheritdoc}
223
     */
224
    public function getPromotionTotal()
225
    {
226
        $promotionTotalElement = $this->getElement('promotion_total');
227
228
        return trim(str_replace('Promotion total:', '', $promotionTotalElement->getText()));
229
    }
230
231
    /**
232
     * {@inheritdoc}
233
     */
234
    public function hasPromotionDiscount($promotionDiscount)
235
    {
236
        $promotionDiscountsText = $this->getElement('promotion_discounts')->getText();
237
238
        return stripos($promotionDiscountsText, $promotionDiscount) !== false;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244
    public function hasShippingPromotion($promotionName)
245
    {
246
        return $this->getElement('promotion_shipping_discounts')->getText();
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252
    public function hasTax($tax)
253
    {
254
        $taxesText = $this->getElement('taxes')->getText();
255
256
        return stripos($taxesText, $tax) !== false;
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262
    public function getItemCode($itemName)
263
    {
264
        return $this->getItemProperty($itemName, 'sylius-product-variant-code');
265
    }
266
267
    /**
268
     * {@inheritdoc}
269
     */
270
    public function getItemUnitPrice($itemName)
271
    {
272
        return $this->getItemProperty($itemName, 'unit-price');
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function getItemDiscountedUnitPrice($itemName)
279
    {
280
        return $this->getItemProperty($itemName, 'discounted-unit-price');
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function getItemQuantity($itemName)
287
    {
288
        return $this->getItemProperty($itemName, 'quantity');
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function getItemSubtotal($itemName)
295
    {
296
        return $this->getItemProperty($itemName, 'subtotal');
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function getItemDiscount($itemName)
303
    {
304
        return $this->getItemProperty($itemName, 'discount');
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310
    public function getItemTax($itemName)
311
    {
312
        return $this->getItemProperty($itemName, 'tax');
313
    }
314
315
    /**
316
     * {@inheritdoc}
317
     */
318
    public function getItemTotal($itemName)
319
    {
320
        return $this->getItemProperty($itemName, 'total');
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326
    public function getPaymentAmount()
327
    {
328
        $paymentsPrice = $this->getElement('payments')->find('css', '.description');
329
330
        return $paymentsPrice->getText();
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function getPaymentsCount()
337
    {
338
        try {
339
            $payments = $this->getElement('payments')->findAll('css', '.item');
340
        } catch (ElementNotFoundException $exception) {
341
            return 0;
342
        }
343
344
        return count($payments);
345
    }
346
347
    /**
348
     * {@inheritdoc}
349
     */
350
    public function getShipmentsCount(): int
351
    {
352
        try {
353
            $shipments = $this->getElement('shipments')->findAll('css', '.item');
354
        } catch (ElementNotFoundException $exception) {
355
            return 0;
356
        }
357
358
        return count($shipments);
359
    }
360
361
    /**
362
     * {@inheritdoc}
363
     */
364
    public function hasCancelButton()
365
    {
366
        return $this->getDocument()->hasButton('Cancel');
367
    }
368
369
    /**
370
     * {@inheritdoc}
371
     */
372
    public function getOrderState()
373
    {
374
        return $this->getElement('order_state')->getText();
375
    }
376
377
    /**
378
     * {@inheritdoc}
379
     */
380
    public function getPaymentState()
381
    {
382
        return $this->getElement('order_payment_state')->getText();
383
    }
384
385
    /**
386
     * {@inheritdoc}
387
     */
388
    public function getShippingState()
389
    {
390
        return $this->getElement('order_shipping_state')->getText();
391
    }
392
393
    public function cancelOrder()
394
    {
395
        $this->getDocument()->pressButton('Cancel');
396
    }
397
398
    public function deleteOrder()
399
    {
400
        $this->getDocument()->pressButton('Delete');
401
    }
402
403
    /**
404
     * {@inheritdoc}
405
     */
406
    public function hasNote($note)
407
    {
408
        $orderNotesElement = $this->getElement('order_notes');
409
410
        return $orderNotesElement->getText() === $note;
411
    }
412
413
    /**
414
     * {@inheritdoc}
415
     */
416
    public function hasShippingProvinceName($provinceName)
417
    {
418
        $shippingAddressText = $this->getElement('shipping_address')->getText();
419
420
        return false !== stripos($shippingAddressText, $provinceName);
421
    }
422
423
    /**
424
     * {@inheritdoc}
425
     */
426
    public function hasBillingProvinceName($provinceName)
427
    {
428
        $billingAddressText = $this->getElement('billing_address')->getText();
429
430
        return false !== stripos($billingAddressText, $provinceName);
431
    }
432
433
    /**
434
     * {@inheritdoc}
435
     */
436
    public function getIpAddressAssigned()
437
    {
438
        return $this->getElement('ip_address')->getText();
439
    }
440
441
    /**
442
     * {@inheritdoc}
443
     */
444
    public function getOrderCurrency()
445
    {
446
        return $this->getElement('currency')->getText();
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452
    public function hasRefundButton()
453
    {
454
        return $this->getDocument()->hasButton('Refund');
455
    }
456
457
    /**
458
     * {@inheritdoc}
459
     */
460
    public function getShippingPromotionData()
461
    {
462
        return $this->getElement('promotion_shipping_discounts')->getText();
463
    }
464
465
    /**
466
     * {@inheritdoc}
467
     */
468
    public function getRouteName()
469
    {
470
        return 'sylius_admin_order_show';
471
    }
472
473
    /**
474
     * {@inheritdoc}
475
     */
476
    protected function getDefinedElements()
477
    {
478
        return array_merge(parent::getDefinedElements(), [
479
            'billing_address' => '#billing-address',
480
            'currency' => '#sylius-order-currency',
481
            'customer' => '#customer',
482
            'ip_address' => '#ipAddress',
483
            'items_total' => '#items-total',
484
            'order_notes' => '#sylius-order-notes',
485
            'order_payment_state' => '#payment-state > span',
486
            'order_shipping_state' => '#shipping-state > span',
487
            'order_state' => '#sylius-order-state',
488
            'payments' => '#sylius-payments',
489
            'promotion_discounts' => '#promotion-discounts',
490
            'promotion_shipping_discounts' => '#promotion-shipping-discounts',
491
            'promotion_total' => '#promotion-total',
492
            'shipments' => '#sylius-shipments',
493
            'shipping_address' => '#shipping-address',
494
            'shipping_charges' => '#shipping-charges',
495
            'shipping_total' => '#shipping-total',
496
            'table' => '.table',
497
            'tax_total' => '#tax-total',
498
            'taxes' => '#taxes',
499
            'total' => '#total',
500
        ]);
501
    }
502
503
    /**
504
     * @return TableAccessorInterface
505
     */
506
    protected function getTableAccessor()
507
    {
508
        return $this->tableAccessor;
509
    }
510
511
    /**
512
     * @param string $elementText
513
     * @param string $customerName
514
     * @param string $street
515
     * @param string $postcode
516
     * @param string $city
517
     * @param string $countryName
518
     *
519
     * @return bool
520
     */
521
    private function hasAddress($elementText, $customerName, $street, $postcode, $city, $countryName)
522
    {
523
        return
524
            (stripos($elementText, $customerName) !== false) &&
525
            (stripos($elementText, $street) !== false) &&
526
            (stripos($elementText, $city) !== false) &&
527
            (stripos($elementText, $countryName . ' ' . $postcode) !== false)
528
        ;
529
    }
530
531
    /**
532
     * @param string $itemName
533
     * @param string $property
534
     *
535
     * @return string
536
     */
537
    private function getItemProperty($itemName, $property)
538
    {
539
        $rows = $this->tableAccessor->getRowsWithFields(
540
            $this->getElement('table'),
541
            ['item' => $itemName]
542
        );
543
544
        return $rows[0]->find('css', '.' . $property)->getText();
545
    }
546
547
    /**
548
     * @param OrderInterface $order
549
     *
550
     * @return NodeElement|null
551
     */
552
    private function getLastOrderPaymentElement(OrderInterface $order)
553
    {
554
        $payment = $order->getPayments()->last();
555
556
        $paymentStateElements = $this->getElement('payments')->findAll('css', sprintf('span.ui.label:contains(\'%s\')', ucfirst($payment->getState())));
557
        $paymentStateElement = end($paymentStateElements);
558
559
        return $paymentStateElement->getParent()->getParent();
560
    }
561
562
    /**
563
     * @param OrderInterface $order
564
     *
565
     * @return NodeElement|null
566
     */
567
    private function getLastOrderShipmentElement(OrderInterface $order)
568
    {
569
        $shipment = $order->getShipments()->last();
570
571
        $shipmentStateElements = $this->getElement('shipments')->findAll('css', sprintf('span.ui.label:contains(\'%s\')', ucfirst($shipment->getState())));
572
        $shipmentStateElement = end($shipmentStateElements);
573
574
        return $shipmentStateElement->getParent()->getParent();
575
    }
576
}
577