Completed
Branch master (b23e60)
by Kamil
35:19
created

SummaryPage   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 263
Duplicated Lines 10.65 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 9
Bugs 0 Features 6
Metric Value
wmc 36
c 9
b 0
f 6
lcom 1
cbo 9
dl 28
loc 263
rs 8.8

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A getRouteName() 0 4 1
A hasItemWithProductAndQuantity() 12 12 2
A hasShippingAddress() 0 6 1
A hasBillingAddress() 0 6 1
A hasShippingMethod() 8 8 2
A hasPaymentMethod() 8 8 2
A hasProductDiscountedUnitPriceBy() 0 15 2
A hasOrderTotal() 0 8 2
A addNotes() 0 4 1
A hasPromotionTotal() 0 4 1
A hasPromotion() 0 4 1
A hasTaxTotal() 0 4 1
A hasShippingTotal() 0 4 1
A getDefinedElements() 0 17 1
A getProductRowElement() 0 4 1
B isAddressValid() 0 14 9
A hasAddressPart() 0 8 3
A getCountryName() 0 4 1
A getPriceFromString() 0 4 1
A getTotalFromString() 0 6 1

How to fix   Duplicated Code   

Duplicated Code

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:

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
namespace Sylius\Behat\Page\Shop\Checkout;
13
14
use Behat\Mink\Session;
15
use Behat\Mink\Element\NodeElement;
16
use Sylius\Behat\Page\SymfonyPage;
17
use Sylius\Behat\Service\Accessor\TableAccessorInterface;
18
use Sylius\Component\Core\Model\AddressInterface;
19
use Sylius\Component\Core\Model\ShippingMethodInterface;
20
use Sylius\Component\Payment\Model\PaymentMethodInterface;
21
use Sylius\Component\Core\Model\ProductInterface;
22
use Symfony\Component\Intl\Intl;
23
use Symfony\Component\Routing\RouterInterface;
24
25
/**
26
 * @author Mateusz Zalewski <[email protected]>
27
 */
28
class SummaryPage extends SymfonyPage implements SummaryPageInterface
29
{
30
    /**
31
     * @var TableAccessorInterface
32
     */
33
    private $tableAccessor;
34
35
    /**
36
     * @param Session $session
37
     * @param array $parameters
38
     * @param RouterInterface $router
39
     * @param TableAccessorInterface $tableAccessor
40
     */
41
    public function __construct(
42
        Session $session,
43
        array $parameters,
44
        RouterInterface $router,
45
        TableAccessorInterface $tableAccessor
46
    ) {
47
        parent::__construct($session, $parameters, $router);
48
49
        $this->tableAccessor = $tableAccessor;
50
    }
51
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getRouteName()
57
    {
58
        return 'sylius_shop_checkout_summary';
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 View Code Duplication
    public function hasItemWithProductAndQuantity($productName, $quantity)
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...
65
    {
66
        $table = $this->getElement('items_table');
67
68
        try {
69
            $this->tableAccessor->getRowWithFields($table, ['item' => $productName, 'qty' => $quantity]);
70
        } catch (\InvalidArgumentException $exception) {
71
            return false;
72
        }
73
74
        return true;
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function hasShippingAddress(AddressInterface $address)
81
    {
82
        $shippingAddress = $this->getElement('shipping_address')->getText();
83
84
        return $this->isAddressValid($shippingAddress, $address);
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function hasBillingAddress(AddressInterface $address)
91
    {
92
        $billingAddress = $this->getElement('billing_address')->getText();
93
94
        return $this->isAddressValid($billingAddress, $address);
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100 View Code Duplication
    public function hasShippingMethod(ShippingMethodInterface $shippingMethod)
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...
101
    {
102
        if (!$this->hasElement('shipping_method')) {
103
            return false;
104
        }
105
106
        return false !== strpos($this->getElement('shipping_method')->getText(), $shippingMethod->getName());
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 View Code Duplication
    public function hasPaymentMethod(PaymentMethodInterface $paymentMethod)
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...
113
    {
114
        if (!$this->hasElement('payment_method')) {
115
            return false;
116
        }
117
118
        return false !== strpos($this->getElement('payment_method')->getText(), $paymentMethod->getName());
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function hasProductDiscountedUnitPriceBy(ProductInterface $product, $amount)
125
    {
126
        $productRowElement = $this->getProductRowElement($product);
127
        $discountedPriceElement = $productRowElement->find('css', 'td > s');
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $discountedPriceElement exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
128
        if (null === $discountedPriceElement) {
129
            return false;
130
        }
131
        $priceElement = $discountedPriceElement->getParent();
132
        $prices = explode(' ', $priceElement->getText());
133
        $priceWithoutDiscount = $this->getPriceFromString($prices[0]);
134
        $priceWithDiscount = $this->getPriceFromString($prices[1]);
135
        $discount = $priceWithoutDiscount - $priceWithDiscount;
136
137
        return $discount === $amount;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function hasOrderTotal($total)
144
    {
145
        if (!$this->hasElement('order_total')) {
146
            return false;
147
        }
148
149
        return $this->getTotalFromString($this->getElement('order_total')->getText()) === $total;
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function addNotes($notes)
156
    {
157
        $this->getElement('extra_notes')->setValue($notes);
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    public function hasPromotionTotal($promotionTotal)
164
    {
165
        return false !== strpos($this->getElement('promotion_total')->getText(), $promotionTotal);
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171
    public function hasPromotion($promotionName)
172
    {
173
        return false !== stripos($this->getElement('promotion_discounts')->getText(), $promotionName);
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179
    public function hasTaxTotal($taxTotal)
180
    {
181
        return false !== strpos($this->getElement('tax_total')->getText(), $taxTotal);
182
    }
183
184
    /**
185
     * {@inheritdoc}
186
     */
187
    public function hasShippingTotal($price)
188
    {
189
        return false !== strpos($this->getElement('shipping_total')->getText(), $price);
190
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195
    protected function getDefinedElements()
196
    {
197
        return array_merge(parent::getDefinedElements(), [
198
            'billing_address' => '#addresses div:contains("Billing address") address',
199
            'extra_notes' =>'#sylius_checkout_summary_notes',
200
            'shipping_address' => '#addresses div:contains("Shipping address") address',
201
            'items_table' => '#items table',
202
            'shipping_method' => '#sylius-checkout-summary-shipping-method',
203
            'payment_method' => '#sylius-checkout-summary-payment-method',
204
            'product_row' => 'tbody tr:contains("%name%")',
205
            'order_total' => 'td:contains("Total")',
206
            'promotion_total' => '#promotion-total',
207
            'promotion_discounts' => '#promotion-discounts',
208
            'tax_total' => '#tax-total',
209
            'shipping_total' => '#shipping-total',
210
        ]);
211
    }
212
213
    /**
214
     * @param ProductInterface $product
215
     *
216
     * @return NodeElement
217
     */
218
    private function getProductRowElement(ProductInterface $product)
219
    {
220
        return $this->getElement('product_row', ['%name%' => $product->getName()]);
221
    }
222
223
    /**
224
     * @param string $displayedAddress
225
     * @param AddressInterface $address
226
     *
227
     * @return bool
228
     */
229
    private function isAddressValid($displayedAddress, AddressInterface $address)
230
    {
231
        return
232
            $this->hasAddressPart($displayedAddress, $address->getCompany(), true) &&
233
            $this->hasAddressPart($displayedAddress, $address->getFirstName()) &&
234
            $this->hasAddressPart($displayedAddress, $address->getLastName()) &&
235
            $this->hasAddressPart($displayedAddress, $address->getPhoneNumber(), true) &&
236
            $this->hasAddressPart($displayedAddress, $address->getStreet()) &&
237
            $this->hasAddressPart($displayedAddress, $address->getCity()) &&
238
            $this->hasAddressPart($displayedAddress, $address->getProvinceCode(), true) &&
239
            $this->hasAddressPart($displayedAddress, $this->getCountryName($address->getCountryCode())) &&
240
            $this->hasAddressPart($displayedAddress, $address->getPostcode())
241
        ;
242
    }
243
244
    /**
245
     * @param string $address
246
     * @param string $addressPart
247
     *
248
     * @return bool
249
     */
250
    private function hasAddressPart($address, $addressPart, $optional = false)
251
    {
252
        if ($optional && null === $addressPart) {
253
            return true;
254
        }
255
256
        return false !== strpos($address, $addressPart);
257
    }
258
259
    /**
260
     * @param string $countryCode
261
     *
262
     * @return string
263
     */
264
    private function getCountryName($countryCode)
265
    {
266
        return strtoupper(Intl::getRegionBundle()->getCountryName($countryCode, 'en'));
267
    }
268
269
    /**
270
     * @param string $price
271
     *
272
     * @return int
273
     */
274
    private function getPriceFromString($price)
275
    {
276
        return (int) round((str_replace(['€', '£', '$'], '', $price) * 100), 2);
277
    }
278
279
    /**
280
     * @param string $total
281
     * 
282
     * @return int
283
     */
284
    private function getTotalFromString($total)
285
    {
286
        $total = str_replace('Total:', '', $total);
287
288
        return $this->getPriceFromString($total);
289
    }
290
}
291