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, |
|
|
|
|
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 |
|
|
|
|
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); |
|
|
|
|
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; |
|
|
|
|
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
|
|
|
|
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:If that code throws an exception and the
EntityManager
is closed. Any other code which depends on the same instance of theEntityManager
during this request will fail.On the other hand, if you instead inject the
ManagerRegistry
, thegetManager()
method guarantees that you will always get a usable manager instance.