Completed
Push — master ( 0b205b...bde6a0 )
by
unknown
10:16
created

OrderStrategy   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 246
Duplicated Lines 8.94 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 3
Bugs 1 Features 1
Metric Value
wmc 39
lcom 1
cbo 10
dl 22
loc 246
rs 8.2857
c 3
b 1
f 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A beforeProcessEntity() 0 9 2
B afterProcessEntity() 0 24 4
B processCustomer() 0 24 5
A processCart() 0 16 3
A processItems() 0 9 2
A processAddresses() 0 9 2
B findRegionEntity() 22 22 4
A findEntityByIdentityValues() 0 11 4
A combineIdentityValues() 0 8 4
D findExistingEntity() 0 37 9

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
namespace OroCRM\Bundle\MagentoBundle\ImportExport\Strategy;
4
5
use Oro\Bundle\AddressBundle\Entity\Region;
6
7
use OroCRM\Bundle\MagentoBundle\Entity\CartStatus;
8
use OroCRM\Bundle\MagentoBundle\Entity\Customer;
9
use OroCRM\Bundle\MagentoBundle\Entity\Order;
10
use OroCRM\Bundle\MagentoBundle\Entity\OrderAddress;
11
use OroCRM\Bundle\MagentoBundle\Provider\MagentoConnectorInterface;
12
use OroCRM\Bundle\MagentoBundle\Entity\OrderItem;
13
14
class OrderStrategy extends AbstractImportStrategy
15
{
16
    const CONTEXT_ORDER_POST_PROCESS_IDS = 'postProcessOrderIds';
17
18
    /**
19
     * @var Order
20
     */
21
    protected $existingEntity;
22
23
    /**
24
     * @param Order $entity
25
     *
26
     * {@inheritdoc}
27
     */
28
    protected function beforeProcessEntity($entity)
29
    {
30
        $this->existingEntity = $this->databaseHelper->findOneByIdentity($entity);
31
        if (!$this->existingEntity) {
32
            $this->existingEntity = $entity;
33
        }
34
35
        return parent::beforeProcessEntity($entity);
36
    }
37
38
    /**
39
     * @param Order $entity
40
     *
41
     * {@inheritdoc}
42
     */
43
    protected function afterProcessEntity($entity)
44
    {
45
        if (!$entity->getUpdatedAt() && $entity->getCreatedAt()) {
46
            $entity->setUpdatedAt($entity->getCreatedAt());
47
        }
48
49
        $now = new \DateTime('now', new \DateTimeZone('UTC'));
50
        if (!$entity->getImportedAt()) {
51
            $entity->setImportedAt($now);
52
        }
53
        $entity->setSyncedAt($now);
54
55
        /** @var Order $order */
56
        $this->processCart($entity);
57
        $this->processItems($entity);
58
        $this->processAddresses($entity);
59
        $this->processCustomer($entity, $entity->getCustomer());
0 ignored issues
show
Documentation introduced by
$entity->getCustomer() is of type object<Oro\Bundle\Busine...ndle\Entity\BasePerson>, but the function expects a null|object<OroCRM\Bundl...Bundle\Entity\Customer>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
60
61
        $this->existingEntity = null;
62
63
        $this->appendDataToContext(self::CONTEXT_ORDER_POST_PROCESS_IDS, $entity->getIncrementId());
64
65
        return parent::afterProcessEntity($entity);
66
    }
67
68
    /**
69
     * @param Order $order
70
     * @param Customer $customer
71
     */
72
    protected function processCustomer(Order $order, Customer $customer = null)
73
    {
74
        if (!$customer || !$customer->getId()) {
75
            $customer = $this->databaseHelper->findOneBy(
76
                'OroCRM\Bundle\MagentoBundle\Entity\Customer',
77
                [
78
                    'email' => $order->getCustomerEmail(),
79
                    'channel' => $order->getChannel()
80
                ]
81
            );
82
        }
83
84
        if ($customer instanceof Customer) {
85
            // now customer orders subtotal calculation support only one currency.
86
            // also we do not take into account order refunds due to magento does not bring subtotal data
87
            // customer currency needs on customer's grid to format lifetime value.
88
            $customer->setCurrency($order->getCurrency());
89
        }
90
        $order->setCustomer($customer);
0 ignored issues
show
Documentation introduced by
$customer is of type object|null, but the function expects a object<Oro\Bundle\Busine...ndle\Entity\BasePerson>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
91
92
        if ($order->getCart()) {
93
            $order->getCart()->setCustomer($customer);
0 ignored issues
show
Bug introduced by
It seems like $customer defined by $this->databaseHelper->f... $order->getChannel())) on line 75 can also be of type object; however, OroCRM\Bundle\MagentoBun...ity\Cart::setCustomer() does only seem to accept null|object<OroCRM\Bundl...Bundle\Entity\Customer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
94
        }
95
    }
96
97
    /**
98
     * If cart exists then add relation to it,
99
     * do nothing otherwise
100
     *
101
     * @param Order $entity
102
     */
103
    protected function processCart(Order $entity)
104
    {
105
        $cart = $entity->getCart();
106
107
        if ($cart) {
108
            $statusClass = MagentoConnectorInterface::CART_STATUS_TYPE;
109
            /** @var CartStatus $purchasedStatus */
110
            $purchasedStatus = $this->databaseHelper
111
                ->findOneBy($statusClass, ['name' => CartStatus::STATUS_PURCHASED]);
112
            if ($purchasedStatus) {
113
                $cart->setStatus($purchasedStatus);
114
            }
115
        }
116
117
        $entity->setCart($cart);
118
    }
119
120
    /**
121
     * @param Order $order
122
     *
123
     * @return OrderStrategy
124
     */
125
    protected function processItems(Order $order)
126
    {
127
        foreach ($order->getItems() as $item) {
128
            $item->setOwner($order->getOrganization());
129
            $item->setOrder($order);
130
        }
131
132
        return $this;
133
    }
134
135
    /**
136
     * @param Order $order
137
     *
138
     * @return OrderStrategy
139
     */
140
    protected function processAddresses(Order $order)
141
    {
142
        /** @var OrderAddress $address */
143
        foreach ($order->getAddresses() as $address) {
144
            $address->setOwner($order);
145
        }
146
147
        return $this;
148
    }
149
150
    /**
151
     * BC layer to find existing collection items by old identity filed values
152
     *
153
     * {@inheritdoc}
154
     */
155
    protected function findExistingEntity($entity, array $searchContext = [])
156
    {
157
        $existingEntity = parent::findExistingEntity($entity, $searchContext);
158
159
        if (!$existingEntity && $entity instanceof OrderAddress) {
160
            /** @var OrderAddress $existingEntity */
161
            $existingEntity = $this->existingEntity->getAddresses()
162
                ->filter(
163
                    function (OrderAddress $address) use ($entity) {
164
                        $isMatched = true;
165
                        $fieldsToMatch = ['street', 'city', 'postalCode', 'country', 'region'];
166
167
                        foreach ($fieldsToMatch as $fieldToMatch) {
168
                            $addressValue = $this->getPropertyAccessor()->getValue($address, $fieldToMatch);
169
                            $entityValue = $this->getPropertyAccessor()->getValue($entity, $fieldToMatch);
170
                            $isMatched = $isMatched && ($addressValue === $entityValue);
171
                        }
172
173
                        return $isMatched;
174
                    }
175
                )
176
                ->first();
177
178
            if ($existingEntity && $entity->getOriginId()) {
179
                $existingEntity->setOriginId($entity->getOriginId());
180
            }
181
        }
182
183
        if ($entity instanceof OrderItem && is_null($entity->getName())) {
184
            //name can't be null, so to avoid import job failing empty string is used
185
            $entity->setName('');
186
        }
187
188
        $existingEntity = $this->findRegionEntity($entity, $existingEntity);
189
190
        return $existingEntity;
191
    }
192
193
    /**
194
     * @param $entity
195
     * @param $existingEntity
196
     *
197
     * @return null|object
198
     */
199 View Code Duplication
    protected function findRegionEntity($entity, $existingEntity)
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...
200
    {
201
        if (!$existingEntity && $entity instanceof Region) {
202
            /** @var \OroCRM\Bundle\MagentoBundle\Entity\Region $magentoRegion */
203
            $magentoRegion = $this->databaseHelper->findOneBy(
204
                'OroCRM\Bundle\MagentoBundle\Entity\Region',
205
                [
206
                    'regionId' => $entity->getCode()
207
                ]
208
            );
209
            if ($magentoRegion) {
210
                $existingEntity = $this->databaseHelper->findOneBy(
211
                    'Oro\Bundle\AddressBundle\Entity\Region',
212
                    [
213
                        'combinedCode' => $magentoRegion->getCombinedCode()
214
                    ]
215
                );
216
            }
217
        }
218
219
        return $existingEntity;
220
    }
221
222
    /**
223
     * Add special identifier for entities not existing in Magento
224
     * Add customer Email to search context for processing related entity Guest Customer for Order
225
     *
226
     * @param string $entityName
227
     * @param array $identityValues
228
     * @return null|object
229
     */
230
    protected function findEntityByIdentityValues($entityName, array $identityValues)
231
    {
232
        if (is_a($entityName, 'OroCRM\Bundle\MagentoBundle\Entity\Customer', true)
233
            && empty($identityValues['originId'])
234
            && $this->existingEntity
235
        ) {
236
            $identityValues['email'] = $this->existingEntity->getCustomerEmail();
237
        }
238
239
        return parent::findEntityByIdentityValues($entityName, $identityValues);
240
    }
241
242
    /**
243
     * Add special search context for entities not existing in Magento
244
     * Add customer Email to search context for Order related entity Guest Customer
245
     *
246
     * @param object $entity
247
     * @param string $entityClass
248
     * @param array $searchContext
249
     * @return array|null
250
     */
251
    protected function combineIdentityValues($entity, $entityClass, array $searchContext)
252
    {
253
        if ($entity instanceof Customer && !$entity->getOriginId() && $this->existingEntity) {
254
            $searchContext['email'] = $this->existingEntity->getCustomerEmail();
255
        }
256
257
        return parent::combineIdentityValues($entity, $entityClass, $searchContext);
258
    }
259
}
260