Passed
Push — master ( 552132...489160 )
by
unknown
03:54
created

loadCustomerByWebsiteIdAndIncrementId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Customer\Observers\CustomerObserver
5
 *
6
 * PHP version 7
7
 *
8
 * @author    Tim Wagner <[email protected]>
9
 * @copyright 2018 TechDivision GmbH <[email protected]>
10
 * @license   https://opensource.org/licenses/MIT
11
 * @link      https://github.com/techdivision/import-customer
12
 * @link      http://www.techdivision.com
13
 */
14
15
namespace TechDivision\Import\Customer\Observers;
16
17
use TechDivision\Import\Observers\CleanUpEmptyColumnsTrait;
18
use TechDivision\Import\Utils\RegistryKeys;
19
use TechDivision\Import\Utils\EntityTypeCodes;
20
use TechDivision\Import\Observers\StateDetectorInterface;
21
use TechDivision\Import\Customer\Utils\GenderKeys;
22
use TechDivision\Import\Customer\Utils\ColumnKeys;
23
use TechDivision\Import\Customer\Utils\MemberNames;
24
use TechDivision\Import\Customer\Services\CustomerBunchProcessorInterface;
25
26
/**
27
 * Observer that create's the customer itself.
28
 *
29
 * @author    Tim Wagner <[email protected]>
30
 * @copyright 2018 TechDivision GmbH <[email protected]>
31
 * @license   https://opensource.org/licenses/MIT
32
 * @link      https://github.com/techdivision/import-customer
33
 * @link      http://www.techdivision.com
34
 */
35
class CustomerObserver extends AbstractCustomerImportObserver
36
{
37
38
    use CleanUpEmptyColumnsTrait;
39
    /**
40
     * The customer bunch processor instance.
41
     *
42
     * @var \TechDivision\Import\Customer\Services\CustomerBunchProcessorInterface
43
     */
44
    protected $customerBunchProcessor;
45
46
    /**
47
     * The array with the available gender keys.
48
     *
49
     * @var array
50
     */
51
    protected $availableGenders = array(
52
        'Male'          => GenderKeys::GENDER_MALE,
53
        'Female'        => GenderKeys::GENDER_FEMALE,
54
        'Not Specified' => GenderKeys::GENDER_NOT_SPECIFIED
55
    );
56
57
    /**
58
     * Initializes the observer with the state detector instance.
59
     *
60
     * @param \TechDivision\Import\Customer\Services\CustomerBunchProcessorInterface $customerBunchProcessor The customer bunch processor instance
61
     * @param \TechDivision\Import\Observers\StateDetectorInterface                  $stateDetector          The state detector instance
62
     */
63
    public function __construct(
64
        CustomerBunchProcessorInterface $customerBunchProcessor,
65
        StateDetectorInterface $stateDetector = null
66
    ) {
67
68
        // set the customer processor and the raw entity loader
69
        $this->customerBunchProcessor = $customerBunchProcessor;
70
71
        // pass the state detector to the parent constructor
72
        parent::__construct($stateDetector);
73
    }
74
75
    /**
76
     * Return's the customer bunch processor instance.
77
     *
78
     * @return \TechDivision\Import\Customer\Services\CustomerBunchProcessorInterface The customer bunch processor instance
79
     */
80
    protected function getCustomerBunchProcessor()
81
    {
82
        return $this->customerBunchProcessor;
83
    }
84
85
    /**
86
     * Process the observer's business logic.
87
     *
88
     * @return void
89
     */
90
    protected function process()
91
    {
92
93
        // load email and website code
94
        $email = $this->getValue(ColumnKeys::EMAIL);
95
        $website = $this->getValue(ColumnKeys::WEBSITE);
96
97
        // query whether or not, we've found a new SKU => means we've found a new customer
98
        if ($this->hasBeenProcessed(array($email, $website))) {
99
            return;
100
        }
101
102
        // prepare the static entity values
103
        $customer = $this->initializeCustomer($this->prepareAttributes());
104
        if ($this->hasChanges($customer)) {
105
            try {
106
                // insert the entity and set the entity ID
107
                $this->setLastEntityId($this->persistCustomer($customer));
108
            } catch (\Exception $e) {
109
                if (!$this->isStrictMode()) {
110
                    $message = sprintf(
111
                        'can\'t import customer with email %s! Error: %s',
112
                        $this->getValue(ColumnKeys::EMAIL),
113
                        $e->getMessage()
114
                    );
115
                    $this->mergeStatus(
116
                        array(
117
                            RegistryKeys::NO_STRICT_VALIDATIONS => array(
118
                                basename($this->getFilename()) => array(
119
                                    $this->getLineNumber() => array(
120
                                        ColumnKeys::EMAIL => $message,
121
                                    ),
122
                                ),
123
                            ),
124
                        )
125
                    );
126
                    $this->skipRow();
127
                } else {
128
                    throw $e;
129
                }
130
            }
131
        } else {
132
            // set the entity ID
133
            $this->setLastEntityId($customer[MemberNames::ENTITY_ID]);
134
        }
135
    }
136
137
    /**
138
     * Prepare the attributes of the entity that has to be persisted.
139
     *
140
     * @return array The prepared attributes
141
     */
142
    protected function prepareAttributes()
143
    {
144
        // initialize the customer values
145
        $email = $this->getValue(ColumnKeys::EMAIL);
146
        $groupId = $this->getValue(ColumnKeys::GROUP_ID);
147
        $storeId = $this->getValue(ColumnKeys::STORE_ID);
148
        $disableAutoGroupChange = $this->getValue(ColumnKeys::DISABLE_AUTO_GROUP_CHANGE);
149
        $prefix = $this->getValue(ColumnKeys::PREFIX);
150
        $firstname = $this->getValue(ColumnKeys::FIRSTNAME);
151
        $middlename = $this->getValue(ColumnKeys::MIDDLENAME);
152
        $lastname = $this->getValue(ColumnKeys::LASTNAME);
153
        $suffix = $this->getValue(ColumnKeys::SUFFIX);
154
        $passwordHash = $this->getValue(ColumnKeys::PASSWORD_HASH);
155
        $rpToken = $this->getValue(ColumnKeys::RP_TOKEN);
156
        $defaultShipping = $this->getValue(ColumnKeys::ADDRESS_DEFAULT_SHIPPING);
157
        $defaultBilling = $this->getValue(ColumnKeys::ADDRESS_DEFAULT_BILLING);
158
        $taxvat = $this->getValue(ColumnKeys::TAXVAT);
159
        $confirmation = $this->getValue(ColumnKeys::CONFIRMATION);
160
        $gender = $this->getGenderByValue($this->getValue(ColumnKeys::GENDER));
161
162
        // load the store id if a store code is present in the current row
163
        if (($storeCode = $this->getValue(ColumnKeys::STORE))) {
164
            $storeId = $this->getStoreIdByCode($storeCode);
165
        }
166
167
        // throw exception if neither the store id nor the store code are available
168
        if ($storeId === null) {
169
            throw new \Exception(
170
                sprintf(
171
                    'Expected value for either _store or store_id, none found in file %s on line %d',
172
                    $this->getFilename(),
173
                    $this->getLineNumber()
174
                )
175
            );
176
        }
177
178
        // load the customer's additional attributes
179
        $createdIn = $this->getValue(ColumnKeys::CREATED_IN);
180
        $isActive = $this->getValue(ColumnKeys::IS_ACTIVE);
181
        $failuresNum = 0;
182
        $firstFailure = null;
183
        $lockExpires = null;
184
185
        // prepare the date format for the created at/updated at dates
186
        $websiteId = $this->getStoreWebsiteIdByCode($this->getValue(ColumnKeys::WEBSITE));
187
        $incrementId = $this->getValue(ColumnKeys::INCREMENT_ID);
188
        $dob = $this->getValue(ColumnKeys::DOB, null, array($this, 'formatDobDate'));
189
        $createdAt = $this->getValue(ColumnKeys::CREATED_AT, date('Y-m-d H:i:s'), array($this, 'formatDate'));
190
        $updatedAt = $this->getValue(ColumnKeys::UPDATED_AT, date('Y-m-d H:i:s'), array($this, 'formatDate'));
191
        $rpTokenCreatedAt = $this->getValue(ColumnKeys::RP_TOKEN_CREATED_AT, null, array($this, 'formatDate'));
192
        $sessionCutoff = $this->getValue(ColumnKeys::SESSION_CUTOFF, null, array($this, 'formatDate'));
193
194
        // return the prepared customer
195
        return $this->initializeEntity(
196
            $this->loadRawEntity(
197
                array(
198
                    MemberNames::WEBSITE_ID                => $websiteId,
199
                    MemberNames::EMAIL                     => $email,
200
                    MemberNames::GROUP_ID                  => $groupId,
201
                    MemberNames::INCREMENT_ID              => $incrementId,
202
                    MemberNames::STORE_ID                  => $storeId,
203
                    MemberNames::CREATED_AT                => $createdAt,
204
                    MemberNames::UPDATED_AT                => $updatedAt,
205
                    MemberNames::IS_ACTIVE                 => $isActive,
206
                    MemberNames::DISABLE_AUTO_GROUP_CHANGE => $disableAutoGroupChange,
207
                    MemberNames::CREATED_IN                => $createdIn,
208
                    MemberNames::PREFIX                    => $prefix,
209
                    MemberNames::FIRSTNAME                 => $firstname,
210
                    MemberNames::MIDDLENAME                => $middlename,
211
                    MemberNames::LASTNAME                  => $lastname,
212
                    MemberNames::SUFFIX                    => $suffix,
213
                    MemberNames::DOB                       => $dob,
214
                    MemberNames::PASSWORD_HASH             => $passwordHash,
215
                    MemberNames::RP_TOKEN                  => $rpToken,
216
                    MemberNames::RP_TOKEN_CREATED_AT       => $rpTokenCreatedAt,
217
                    MemberNames::DEFAULT_BILLING           => $defaultBilling,
218
                    MemberNames::DEFAULT_SHIPPING          => $defaultShipping,
219
                    MemberNames::TAXVAT                    => $taxvat,
220
                    MemberNames::CONFIRMATION              => $confirmation,
221
                    MemberNames::GENDER                    => $gender,
222
                    MemberNames::FAILURES_NUM              => $failuresNum,
223
                    MemberNames::FIRST_FAILURE             => $firstFailure,
224
                    MemberNames::LOCK_EXPIRES              => $lockExpires,
225
                    MemberNames::SESSION_CUTOFF           => $sessionCutoff
226
                )
227
            )
228
        );
229
    }
230
231
    /**
232
     * Load's and return's a raw customer entity without primary key but the mandatory members only and nulled values.
233
     *
234
     * @param array $data An array with data that will be used to initialize the raw entity with
235
     *
236
     * @return array The initialized entity
237
     */
238
    protected function loadRawEntity(array $data = array())
239
    {
240
        return $this->getCustomerBunchProcessor()->loadRawEntity(EntityTypeCodes::CUSTOMER, $data);
241
    }
242
243
    /**
244
     * Initialize the customer with the passed attributes and returns an instance.
245
     *
246
     * @param array $attr The customer attributes
247
     *
248
     * @return array The initialized customer
249
     */
250
    protected function initializeCustomer(array $attr)
251
    {
252
253
        // load the customer with the passed email and website ID and merge it with the attributes
254
        if ($entity = $this->loadCustomerByEmailAndWebsiteId($attr[MemberNames::EMAIL], $attr[MemberNames::WEBSITE_ID])) {
255
            // clear row elements that are not allowed to be updated
256
            $attr = $this->clearRowData($attr, true);
257
258
            // remove the created at date from the attributes, when we update the entity
259
            unset($attr[MemberNames::CREATED_AT]);
260
261
            return $this->mergeEntity($entity, $attr);
262
263
            // try to load the customer with the given increment ID and the website id
264
        } elseif (!empty($attr[MemberNames::INCREMENT_ID])  && $entity = $this->loadCustomerByWebsiteIdAndIncrementId($attr[MemberNames::WEBSITE_ID], $attr[MemberNames::INCREMENT_ID])) {
265
            // clear row elements that are not allowed to be updated
266
            $attr = $this->clearRowData($attr, true);
267
268
            // remove the created at date from the attributes, when we update the entity
269
            unset($attr[MemberNames::CREATED_AT]);
270
271
            return $this->mergeEntity($entity, $attr);
272
        } else {
273
            // cleanup __EMPTY__VALUE__ entries, don't remove array elements
274
            $attr = $this->clearRowData($attr, false);
275
        }
276
277
        
278
        // New Customer always active
279
        if ($attr[MemberNames::IS_ACTIVE] == null) {
280
            $attr[MemberNames::IS_ACTIVE] = 1;
281
        }
282
283
        // otherwise simply return the attributes
284
        return $attr;
285
    }
286
287
    /**
288
     * Return's the gender ID for the passed value.
289
     *
290
     * @param string $value The value to return the gender ID for
291
     *
292
     * @return integer The gender ID
293
     * @throws \Exception Is thrown, if the gender ID with the requested value is not available
294
     */
295
    protected function getGenderByValue($value)
296
    {
297
298
        // query whether or not, the requested gender ID is available
299
        if (isset($this->availableGenders[$value])) {
300
            return (integer) $this->availableGenders[$value];
301
        }
302
303
        // allow null values and empty strings
304
        if ($value === null || $value === '') {
305
            return null;
306
        }
307
308
        // throw an exception, if not
309
        throw new \Exception(
310
            $this->appendExceptionSuffix(
311
                sprintf('Found invalid gender %s', $value)
312
            )
313
        );
314
    }
315
316
    /**
317
     * Returns the store id for the specified store code.
318
     *
319
     * @param string $code The store code
320
     *
321
     * @return integer The store id
322
     */
323
    protected function getStoreIdByCode($code)
324
    {
325
        return $this->getSubject()->getStoreId($code);
326
    }
327
328
    /**
329
     * Return's the store website for the passed code.
330
     *
331
     * @param string $code The code of the store website to return the ID for
332
     *
333
     * @return integer The store website ID
334
     */
335
    protected function getStoreWebsiteIdByCode($code)
336
    {
337
        return $this->getSubject()->getStoreWebsiteIdByCode($code);
338
    }
339
340
    /**
341
     * Return's the customer with the passed email and website ID.
342
     *
343
     * @param string $email     The email of the customer to return
344
     * @param string $websiteId The website ID of the customer to return
345
     *
346
     * @return array|null The customer
347
     */
348
    protected function loadCustomerByEmailAndWebsiteId($email, $websiteId)
349
    {
350
        return $this->getCustomerBunchProcessor()->loadCustomerByEmailAndWebsiteId($email, $websiteId);
351
    }
352
353
    /**
354
     * Return's the customer with the passed increment ID and website ID.
355
     *
356
     * @param string $incrementId The increment ID of the customer to return
357
     * @param string $websiteId   The website ID of the customer to return
358
     *
359
     * @return array|null The customer
360
     */
361
    protected function loadCustomerByWebsiteIdAndIncrementId($websiteId, $incrementId)
362
    {
363
        return $this->getCustomerBunchProcessor()->loadCustomerByWebsiteIdAndIncrementId($websiteId, $incrementId);
364
    }
365
366
    /**
367
     * Persist's the passed customer data and return's the ID.
368
     *
369
     * @param array $customer The customer data to persist
370
     *
371
     * @return string The ID of the persisted entity
372
     */
373
    protected function persistCustomer($customer)
374
    {
375
        return $this->getCustomerBunchProcessor()->persistCustomer($customer);
376
    }
377
378
    /**
379
     * Return's the attribute set of the customer that has to be created.
380
     *
381
     * @return array The attribute set
382
     */
383
    protected function getAttributeSet()
384
    {
385
        return $this->getSubject()->getAttributeSet();
386
    }
387
388
    /**
389
     * Set's the ID of the customer that has been created recently.
390
     *
391
     * @param string $lastEntityId The entity ID
392
     *
393
     * @return void
394
     */
395
    protected function setLastEntityId($lastEntityId)
396
    {
397
        $this->getSubject()->setLastEntityId($lastEntityId);
398
    }
399
400
    /**
401
     * @param string $value DOB value
402
     *
403
     * @return null|string
404
     */
405
    protected function formatDobDate($value)
406
    {
407
        // try to format the date according to the configured date format
408
        $formattedDate = $this->getSubject()->getDateConverter()->convert($value);
409
410
        $format = 'Y-m-d H:i:s';
411
        $dateTime = \DateTime::createFromFormat($format, $formattedDate);
412
413
        if (!$dateTime) {
0 ignored issues
show
introduced by
$dateTime is of type DateTime, thus it always evaluated to true.
Loading history...
414
            return null;
415
        }
416
417
        // return the formatted date for birthday
418
        return $dateTime->format('Y-m-d');
419
    }
420
}
421