Completed
Push — 1.10 ( 93e51c...7f32fb )
by
unknown
11:06
created

updateAddressByDataFromMagento()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 5
nc 1
nop 2
1
<?php
2
3
namespace OroCRM\Bundle\MagentoBundle\Manager;
4
5
use Doctrine\ORM\EntityManager;
6
7
use Psr\Log\LoggerAwareInterface;
8
use Psr\Log\LoggerAwareTrait;
9
10
use Symfony\Component\PropertyAccess\PropertyAccess;
11
use Symfony\Component\PropertyAccess\PropertyAccessor;
12
13
use Oro\Bundle\ImportExportBundle\Context\Context;
14
use Oro\Bundle\IntegrationBundle\Entity\Channel;
15
16
use OroCRM\Bundle\ContactBundle\Entity\Contact;
17
use OroCRM\Bundle\ContactBundle\Entity\ContactAddress;
18
use OroCRM\Bundle\MagentoBundle\Entity\Address;
19
use OroCRM\Bundle\MagentoBundle\Entity\Customer;
20
use OroCRM\Bundle\MagentoBundle\Exception\ManyAddressesException;
21
use OroCRM\Bundle\MagentoBundle\ImportExport\Converter\CustomerAddressDataConverter;
22
use OroCRM\Bundle\MagentoBundle\ImportExport\Processor\ContextProcessor;
23
use OroCRM\Bundle\MagentoBundle\ImportExport\Strategy\CustomerAddressStrategy;
24
use OroCRM\Bundle\MagentoBundle\Manager\CustomerAddress\ConvertAddressToContactAdress;
25
use OroCRM\Bundle\MagentoBundle\Provider\Transport\MagentoTransportInterface;
26
27
class CustomerInfoManager implements LoggerAwareInterface
28
{
29
    use LoggerAwareTrait;
30
31
    /** @var EntityManager */
32
    protected $em;
33
34
    /** @var PropertyAccessor  */
35
    protected $accessor;
36
37
    /** @var MagentoTransportInterface */
38
    protected $transport;
39
40
    /** @var CustomerAddressDataConverter */
41
    protected $customerAddressDataConverter;
42
43
    /** @var  CustomerAddressStrategy */
44
    protected $customerAddressStrategy;
45
46
    /** @var  ContextProcessor */
47
    protected $contextProcessor;
48
49
    /** @var ConvertAddressToContactAdress */
50
    protected $convertAddressToContactAdress;
51
52
    protected $baseAddressProperties = [
53
        'label',
54
        'street',
55
        'street2',
56
        'city',
57
        'postalCode',
58
        'country',
59
        'organization',
60
        'region',
61
        'regionText',
62
        'namePrefix',
63
        'firstName',
64
        'middleName',
65
        'lastName',
66
        'nameSuffix',
67
        'types'
68
    ];
69
70
    /**
71
     * @param EntityManager $em
72
     * @param MagentoTransportInterface $transport
73
     * @param CustomerAddressDataConverter $customerAddressDataConverter
74
     * @param CustomerAddressStrategy $customerAddressStrategy
75
     * @param ContextProcessor $contextProcessor
76
     * @param ConvertAddressToContactAdress $convertAddressToContactAdress
77
     */
78
    public function __construct(
79
        EntityManager $em,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
80
        MagentoTransportInterface $transport,
81
        CustomerAddressDataConverter $customerAddressDataConverter,
82
        CustomerAddressStrategy $customerAddressStrategy,
83
        ContextProcessor $contextProcessor,
84
        ConvertAddressToContactAdress $convertAddressToContactAdress
85
    ) {
86
        $this->em = $em;
87
        $this->accessor = PropertyAccess::createPropertyAccessor();
88
        $this->transport = $transport;
89
        $this->customerAddressDataConverter = $customerAddressDataConverter;
90
        $this->customerAddressStrategy = $customerAddressStrategy;
91
        $this->contextProcessor = $contextProcessor;
92
        $this->convertAddressToContactAdress = $convertAddressToContactAdress;
93
    }
94
95
    /**
96
     * @param int[] $integrationIds
0 ignored issues
show
Documentation introduced by
There is no parameter named $integrationIds. Did you maybe mean $integrationId?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
97
     * @param int[]|null $customersIds
98
     * @param int $batchSize
99
     */
100
    public function reSyncData($integrationId, $customersIds = null, $batchSize = 25)
101
    {
102
        $i = 0;
103
        $this->logger->info('Start process');
104
        $iterator = $this->getCustomerIterator($customersIds, $integrationId);
105
        $repositoryIntegrationChannel = $this->em->getRepository('OroIntegrationBundle:Channel');
106
        $integration = $repositoryIntegrationChannel->find($integrationId);
107
108
        $this->transport->init($integration->getTransport());
109
        $iterator->setBufferSize($batchSize);
110
        $customerCount = $iterator->count();
111
        $iterator->setPageCallback(function () use (&$i, $customerCount) {
112
            $this->em->flush();
113
            $this->logger->info(sprintf('Processed %s customers from %s', $i, $customerCount));
114
        });
115
116
        /** @var Customer $customer */
117
        foreach ($iterator as $customer) {
118
            $i++;
119
            if ($customer->getOriginId()) {
120
                $magentoCustomerAddresses = $this->transport->getCustomerAddresses($customer->getOriginId());
121
                $contact = $customer->getContact();
122
123
                foreach ($magentoCustomerAddresses as $data) {
124
                    try {
125
                        /** @var Address $address */
126
                        $address = $this->convertDataIntoAddress($data, $integration);
0 ignored issues
show
Documentation introduced by
$integration is of type object|null, but the function expects a object<Oro\Bundle\Integr...nBundle\Entity\Channel>.

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...
127
                        $address->setOwner($customer);
128
                        if ($customer->getAddresses()->count() === 0) {
129
                            $address->setPrimary(true);
130
                            $customer->addAddress($address);
131
                        }
132
133
                        $customerAddress = $this->findCustomerAddress($customer, $address->getOriginId());
134
135
                        if ($customerAddress) {
136
                            $address = $this->updateAddressByDataFromMagento($customerAddress, $address);
137
138
                            if ($contact) {
139
                                $contactAddress = $this->handleContactAddress($customerAddress, $address, $contact);
140
                                $address->setContactAddress($contactAddress);
141
                                $this->em->persist($contactAddress);
142
                            }
143
                        } else {
144
                            if ($contact) {
145
                                $contactAddress = $this->convertAddressToContactAdress->convert($address);
146
                                $contactAddress->setOwner($contact);
147
148
                                $address->setContactAddress($contactAddress);
149
                                $address->setContactPhone($customer->getContact()->getPrimaryPhone());
150
                                $this->em->persist($contactAddress);
151
                            }
152
                        }
153
154
                        $this->em->persist($address);
155
                    } catch (ManyAddressesException $e) {
156
                        $this->logger->info($e->getMessage());
157
                    }
158
                }
159
            }
160
        }
161
162
        $this->em->flush();
163
        $this->logger->info(sprintf('Finish process'));
164
    }
165
166
    /**
167
     * @param $customersIds
168
     * @param $integrationIds
169
     *
170
     * @return \Oro\Bundle\BatchBundle\ORM\Query\BufferedQueryResultIterator
171
     */
172
    protected function getCustomerIterator($customersIds, $integrationId)
173
    {
174
        $repository = $this->em->getRepository('OroCRMMagentoBundle:Customer');
175
176
        return $repository->getIteratorByIdsAndIntegrationIds($customersIds, [$integrationId]);
177
    }
178
179
    /**
180
     * @param Address $customerAddress
181
     * @param Contact $contact
182
     *
183
     * @return ContactAddress
184
     */
185
    protected function createContactAddress(Address $customerAddress, Contact $contact)
186
    {
187
        $newContactAddress = new ContactAddress();
188
        $this->copyProperties($this->baseAddressProperties, $newContactAddress, $customerAddress);
189
        $newContactAddress->setOwner($contact);
190
        $newContactAddress->setPrimary($customerAddress->isPrimary());
191
192
        return $newContactAddress;
193
    }
194
195
    /**
196
     * @param ContactAddress $contactAddress
197
     * @param Address $customerAddress
198
     *
199
     * @return ContactAddress
200
     */
201
    protected function updateContactAddress(ContactAddress $contactAddress, Address $customerAddress)
202
    {
203
        $this->copyProperties($this->baseAddressProperties, $contactAddress, $customerAddress);
204
205
        return $contactAddress;
206
    }
207
208
    /**
209
     * @param array $listProperties
210
     * @param $firstEntity
211
     * @param $secondEntity
212
     */
213
    protected function copyProperties($listProperties, $firstEntity, $secondEntity)
214
    {
215
        foreach ($listProperties as $property) {
216
            try {
217
                $this->accessor->setValue(
218
                    $firstEntity,
219
                    $property,
220
                    $this->accessor->getValue($secondEntity, $property)
221
                );
222
            } catch (\Exception $e) {
223
                $this->logger->info($e->getMessage());
224
            }
225
        }
226
    }
227
228
    /**
229
     * @param Address $customerAddress
230
     * @param Address $magentoAddress
231
     *
232
     * @return Address
233
     */
234
    protected function updateAddressByDataFromMagento(Address $customerAddress, Address $magentoAddress)
235
    {
236
        $properties = $this->baseAddressProperties;
237
        $properties[] = 'phone';
238
239
        $this->copyProperties($properties, $customerAddress, $magentoAddress);
240
241
        return $customerAddress;
242
    }
243
244
    /**
245
     * @return $this
246
     */
247
    protected function getContextProcessor()
248
    {
249
        $entityName = 'OroCRM\Bundle\MagentoBundle\Entity\Address';
250
        $this->contextProcessor->setEntityName($entityName);
251
        $this->customerAddressStrategy->setEntityName($entityName);
252
        $this->contextProcessor->setStrategy($this->customerAddressStrategy);
253
254
        return $this;
255
    }
256
257
    /**
258
     * @param $context
259
     *
260
     * @return $this
261
     */
262
    protected function setContext($context)
263
    {
264
        $this->contextProcessor->setImportExportContext($context);
265
266
        return $this;
267
    }
268
269
    /**
270
     * @param Customer $customer
271
     * @param $id
272
     *
273
     * @return Address|null
274
     * @throws \Exception
275
     */
276
    protected function findCustomerAddress(Customer $customer, $id)
277
    {
278
        $address = $customer->getAddresses()->filter(function (Address $address) use ($id) {
279
            return $address->getOriginId() === $id;
280
        });
281
282
        switch (true) {
283
            case ($address->count() === 1):
284
                $response = $address->first();
285
                break;
286
            case ($address->count() > 1):
287
                throw new ManyAddressesException("Customer has serveral address with origin id " . $id);
288
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
289
            default:
290
                $response = null;
291
        }
292
293
        return $response;
294
    }
295
296
    /**
297
     * @param array $data
298
     * @param Channel $integration
299
     *
300
     * @return mixed|null
301
     */
302
    protected function convertDataIntoAddress($data, Channel $integration)
303
    {
304
        $customerAddress = $this->customerAddressDataConverter->convertToImportFormat($data);
305
        $customerAddress['channel'] = ['id' => $integration->getId()];
306
307
        $context = new Context([]);
308
        $context->setValue('itemData', $customerAddress);
309
310
        $this->getContextProcessor()->setContext($context);
311
312
        return $this->contextProcessor->process($customerAddress);
313
    }
314
315
    /**
316
     * @param Address $customerAddress
317
     * @param Address $address
318
     * @param Contact $contact
319
     *
320
     * @return ContactAddress
321
     */
322
    private function handleContactAddress($customerAddress, $address, $contact)
323
    {
324
        if ($customerAddress->getContactAddress()) {
325
            $contactAddress = $this->updateContactAddress(
326
                $customerAddress->getContactAddress(),
327
                $address
328
            );
329
        } else {
330
            $contactAddress = $this->createContactAddress($address, $contact);
331
        }
332
333
        return $contactAddress;
334
    }
335
}
336