Issues (3641)

User/src/Spryker/Zed/User/Business/Model/User.php (1 issue)

1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\User\Business\Model;
9
10
use Generated\Shared\Transfer\CollectionTransfer;
11
use Generated\Shared\Transfer\UserCollectionTransfer;
12
use Generated\Shared\Transfer\UserCriteriaTransfer;
13
use Generated\Shared\Transfer\UserTransfer;
14
use Orm\Zed\User\Persistence\Map\SpyUserTableMap;
15
use Orm\Zed\User\Persistence\SpyUser;
16
use Spryker\Client\Session\SessionClientInterface;
17
use Spryker\Zed\Kernel\Persistence\EntityManager\TransactionTrait;
18
use Spryker\Zed\User\Business\Exception\PasswordEncryptionFailedException;
19
use Spryker\Zed\User\Business\Exception\UsernameExistsException;
20
use Spryker\Zed\User\Business\Exception\UserNotFoundException;
21
use Spryker\Zed\User\Persistence\UserQueryContainerInterface;
22
use Spryker\Zed\User\UserConfig;
23
24
class User implements UserInterface
25
{
26
    use TransactionTrait;
27
28
    /**
29
     * @var string
30
     */
31
    public const USER_BUNDLE_SESSION_KEY = 'user';
32
33
    /**
34
     * @var \Spryker\Zed\User\Persistence\UserQueryContainerInterface
35
     */
36
    protected $queryContainer;
37
38
    /**
39
     * @var \Spryker\Client\Session\SessionClientInterface
40
     */
41
    protected $session;
42
43
    /**
44
     * @var \Spryker\Zed\User\UserConfig
45
     */
46
    protected $userConfig;
47
48
    /**
49
     * @var array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserPostSavePluginInterface>
50
     */
51
    protected $userPostSavePlugins;
52
53
    /**
54
     * @var array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserPreSavePluginInterface>
55
     */
56
    protected $userPreSavePlugins;
57
58
    /**
59
     * @deprecated Use {@link \Spryker\Zed\User\Business\Model\User::$userExpanderPlugins} instead.
60
     *
61
     * @var array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserTransferExpanderPluginInterface>
62
     */
63
    protected $userTransferExpanderPlugins;
64
65
    /**
66
     * @var array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserExpanderPluginInterface>
67
     */
68
    protected array $userExpanderPlugins;
69
70
    /**
71
     * @param \Spryker\Zed\User\Persistence\UserQueryContainerInterface $queryContainer
72
     * @param \Spryker\Client\Session\SessionClientInterface $session
73
     * @param \Spryker\Zed\User\UserConfig $userConfig
74
     * @param array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserPostSavePluginInterface> $userPostSavePlugins
75
     * @param array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserPreSavePluginInterface> $userPreSavePlugins
76
     * @param array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserTransferExpanderPluginInterface> $userTransferExpanderPlugins
77
     * @param array<\Spryker\Zed\UserExtension\Dependency\Plugin\UserExpanderPluginInterface> $userExpanderPlugins
78
     */
79
    public function __construct(
80
        UserQueryContainerInterface $queryContainer,
81
        SessionClientInterface $session,
82
        UserConfig $userConfig,
83
        array $userPostSavePlugins = [],
84
        array $userPreSavePlugins = [],
85
        array $userTransferExpanderPlugins = [],
86
        array $userExpanderPlugins = []
87
    ) {
88
        $this->queryContainer = $queryContainer;
89
        $this->session = $session;
90
        $this->userConfig = $userConfig;
91
        $this->userPostSavePlugins = $userPostSavePlugins;
92
        $this->userPreSavePlugins = $userPreSavePlugins;
93
        $this->userTransferExpanderPlugins = $userTransferExpanderPlugins;
94
        $this->userExpanderPlugins = $userExpanderPlugins;
95
    }
96
97
    /**
98
     * @param string $firstName
99
     * @param string $lastName
100
     * @param string $username
101
     * @param string $password
102
     *
103
     * @throws \Spryker\Zed\User\Business\Exception\UsernameExistsException
104
     *
105
     * @return \Generated\Shared\Transfer\UserTransfer
106
     */
107
    public function addUser($firstName, $lastName, $username, $password)
108
    {
109
        $userCheck = $this->hasUserByUsername($username);
110
111
        if ($userCheck === true) {
112
            throw new UsernameExistsException();
113
        }
114
115
        $transferUser = new UserTransfer();
116
        $transferUser->setFirstName($firstName);
117
        $transferUser->setLastName($lastName);
118
        $transferUser->setUsername($username);
119
        $transferUser->setPassword($password);
120
121
        return $this->save($transferUser);
122
    }
123
124
    /**
125
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
126
     *
127
     * @throws \Spryker\Zed\User\Business\Exception\UsernameExistsException
128
     *
129
     * @return \Generated\Shared\Transfer\UserTransfer
130
     */
131
    public function createUser(UserTransfer $userTransfer): UserTransfer
132
    {
133
        $userCheck = $this->hasUserByUsername($userTransfer->getUsernameOrFail());
134
135
        if ($userCheck === true) {
136
            throw new UsernameExistsException(
137
                sprintf('Username %s already exist.', $userTransfer->getUsername()),
138
            );
139
        }
140
141
        return $this->save($userTransfer);
142
    }
143
144
    /**
145
     * @param string $password
146
     *
147
     * @return string|false
148
     */
149
    public function encryptPassword($password)
150
    {
151
        return password_hash($password, PASSWORD_BCRYPT);
152
    }
153
154
    /**
155
     * @param string $password
156
     * @param string $hash
157
     *
158
     * @return bool
159
     */
160
    public function validatePassword($password, $hash)
161
    {
162
        return password_verify($password, $hash);
163
    }
164
165
    /**
166
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
167
     *
168
     * @return \Generated\Shared\Transfer\UserTransfer
169
     */
170
    public function save(UserTransfer $userTransfer)
171
    {
172
        return $this->getTransactionHandler()->handleTransaction(function () use ($userTransfer): UserTransfer {
173
            return $this->executeSaveTransaction($userTransfer);
174
        });
175
    }
176
177
    /**
178
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
179
     *
180
     * @throws \Spryker\Zed\User\Business\Exception\PasswordEncryptionFailedException
181
     *
182
     * @return \Generated\Shared\Transfer\UserTransfer
183
     */
184
    protected function executeSaveTransaction(UserTransfer $userTransfer): UserTransfer
185
    {
186
        if ($userTransfer->getIdUser() !== null) {
187
            $userEntity = $this->getEntityUserById($userTransfer->getIdUser());
188
        } else {
189
            $userEntity = new SpyUser();
190
        }
191
192
        $userTransfer = $this->executePreSavePlugins($userTransfer);
193
        $modifiedUser = $userTransfer->modifiedToArray();
194
195
        unset($modifiedUser[UserTransfer::PASSWORD]);
196
197
        $userEntity->fromArray($modifiedUser);
198
199
        $password = $userTransfer->getPassword();
200
        if ($password && $this->isRawPassword($password)) {
201
            $passwordEncrypted = $this->encryptPassword($password);
202
            if ($passwordEncrypted === false) {
0 ignored issues
show
The condition $passwordEncrypted === false is always false.
Loading history...
203
                throw new PasswordEncryptionFailedException();
204
            }
205
206
            $userEntity->setPassword($passwordEncrypted);
207
        }
208
209
        $userEntity->save();
210
        $userTransfer = $this->entityToTransfer($userEntity);
211
        $userTransfer = $this->executePostSavePlugins($userTransfer);
212
213
        return $userTransfer;
214
    }
215
216
    /**
217
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
218
     *
219
     * @return \Generated\Shared\Transfer\UserTransfer
220
     */
221
    protected function executePreSavePlugins(UserTransfer $userTransfer): UserTransfer
222
    {
223
        foreach ($this->userPreSavePlugins as $preSavePlugin) {
224
            $userTransfer = $preSavePlugin->preSave($userTransfer);
225
        }
226
227
        return $userTransfer;
228
    }
229
230
    /**
231
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
232
     *
233
     * @return \Generated\Shared\Transfer\UserTransfer
234
     */
235
    protected function executePostSavePlugins(UserTransfer $userTransfer): UserTransfer
236
    {
237
        foreach ($this->userPostSavePlugins as $postSavePlugin) {
238
            $userTransfer = $postSavePlugin->postSave($userTransfer);
239
        }
240
241
        return $userTransfer;
242
    }
243
244
    /**
245
     * @param int $idUser
246
     *
247
     * @return \Generated\Shared\Transfer\UserTransfer
248
     */
249
    public function removeUser($idUser)
250
    {
251
        $user = $this->getUserById($idUser);
252
        $user->setStatus('deleted');
253
254
        return $this->save($user);
255
    }
256
257
    /**
258
     * @param string $password
259
     *
260
     * @return bool
261
     */
262
    private function isRawPassword($password)
263
    {
264
        $passwordInfo = password_get_info($password);
265
266
        return $passwordInfo['algoName'] === 'unknown';
267
    }
268
269
    /**
270
     * @param string $username
271
     *
272
     * @return bool
273
     */
274
    public function hasUserByUsername($username)
275
    {
276
        $amount = $this->queryContainer->queryUserByUsername($username)->count();
277
278
        return $amount > 0;
279
    }
280
281
    /**
282
     * @param string $username
283
     *
284
     * @return bool
285
     */
286
    public function hasActiveUserByUsername($username)
287
    {
288
        $amount = $this->queryContainer->queryUserByUsername($username)
289
            ->filterByStatus(SpyUserTableMap::COL_STATUS_ACTIVE)->count();
290
291
        return $amount > 0;
292
    }
293
294
    /**
295
     * @param int $idUser
296
     *
297
     * @return bool
298
     */
299
    public function hasUserById($idUser)
300
    {
301
        $amount = $this->queryContainer->queryUserById($idUser)->count();
302
303
        return $amount > 0;
304
    }
305
306
    /**
307
     * @deprecated Use {@link \Spryker\Zed\User\Business\Reader\UserReader::getUserCollection()} instead.
308
     *
309
     * @param string $username
310
     *
311
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
312
     *
313
     * @return \Generated\Shared\Transfer\UserTransfer
314
     */
315
    public function getUserByUsername($username)
316
    {
317
        $entity = $this->queryContainer->queryUserByUsername($username)->findOne();
318
319
        if ($entity === null) {
320
            throw new UserNotFoundException();
321
        }
322
323
        return $this->entityToTransfer($entity);
324
    }
325
326
    /**
327
     * @deprecated Use {@link \Spryker\Zed\User\Business\Reader\UserReader::getUserCollection()} instead.
328
     *
329
     * @param int $id
330
     *
331
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
332
     *
333
     * @return \Generated\Shared\Transfer\UserTransfer
334
     */
335
    public function getUserById($id)
336
    {
337
        $entity = $this->queryContainer
338
            ->queryUserById($id)
339
            ->findOne();
340
341
        if ($entity === null) {
342
            throw new UserNotFoundException();
343
        }
344
345
        return $this->entityToTransfer($entity);
346
    }
347
348
    /**
349
     * @deprecated Use {@link \Spryker\Zed\User\Business\Model\User::findUser()} instead.
350
     *
351
     * @param int $id
352
     *
353
     * @return \Generated\Shared\Transfer\UserTransfer|null
354
     */
355
    public function findUserById(int $id): ?UserTransfer
356
    {
357
        return $this->findUserByIdUser($id);
358
    }
359
360
    /**
361
     * @deprecated Use {@link \Spryker\Zed\User\Business\Reader\UserReader::getUserCollection()} instead.
362
     *
363
     * @param \Generated\Shared\Transfer\UserCriteriaTransfer $userCriteriaTransfer
364
     *
365
     * @return \Generated\Shared\Transfer\UserTransfer|null
366
     */
367
    public function findUser(UserCriteriaTransfer $userCriteriaTransfer): ?UserTransfer
368
    {
369
        if ($userCriteriaTransfer->getIdUser() !== null) {
370
            return $this->findUserByIdUser($userCriteriaTransfer->getIdUser());
371
        }
372
373
        if ($userCriteriaTransfer->getEmail() !== null) {
374
            return $this->findUserByEmail($userCriteriaTransfer->getEmail());
375
        }
376
377
        return null;
378
    }
379
380
    /**
381
     * @param int $idUser
382
     *
383
     * @return \Generated\Shared\Transfer\UserTransfer|null
384
     */
385
    protected function findUserByIdUser(int $idUser): ?UserTransfer
386
    {
387
        $userEntity = $this->queryContainer
388
            ->queryUserById($idUser)
389
            ->findOne();
390
391
        if (!$userEntity) {
392
            return null;
393
        }
394
395
        return $this->entityToTransfer($userEntity);
396
    }
397
398
    /**
399
     * @param string $email
400
     *
401
     * @return \Generated\Shared\Transfer\UserTransfer|null
402
     */
403
    protected function findUserByEmail(string $email): ?UserTransfer
404
    {
405
        $userEntity = $this->queryContainer
406
            ->queryUserByUsername($email)
407
            ->findOne();
408
409
        if (!$userEntity) {
410
            return null;
411
        }
412
413
        return $this->entityToTransfer($userEntity);
414
    }
415
416
    /**
417
     * @deprecated Use {@link \Spryker\Zed\User\Business\Reader\UserReader::getUserCollection()} instead.
418
     *
419
     * @param int $id
420
     *
421
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
422
     *
423
     * @return \Generated\Shared\Transfer\UserTransfer
424
     */
425
    public function getActiveUserById($id)
426
    {
427
        $entity = $this->queryContainer
428
            ->queryUserById($id)
429
            ->filterByStatus(SpyUserTableMap::COL_STATUS_ACTIVE)
430
            ->findOne();
431
432
        if ($entity === null) {
433
            throw new UserNotFoundException();
434
        }
435
436
        return $this->entityToTransfer($entity);
437
    }
438
439
    /**
440
     * @param int $id
441
     *
442
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
443
     *
444
     * @return \Orm\Zed\User\Persistence\SpyUser
445
     */
446
    public function getEntityUserById($id)
447
    {
448
        $entity = $this->queryContainer->queryUserById($id)->findOne();
449
450
        if ($entity === null) {
451
            throw new UserNotFoundException();
452
        }
453
454
        return $entity;
455
    }
456
457
    /**
458
     * @param \Generated\Shared\Transfer\UserTransfer $user
459
     *
460
     * @return mixed
461
     */
462
    public function setCurrentUser(UserTransfer $user)
463
    {
464
        $key = $this->createUserKey();
465
466
        return $this->session->set($key, clone $user);
467
    }
468
469
    /**
470
     * @return bool
471
     */
472
    public function hasCurrentUser()
473
    {
474
        $user = $this->readUserFromSession();
475
476
        return $user !== null;
477
    }
478
479
    /**
480
     * @return \Generated\Shared\Transfer\UserTransfer|null
481
     */
482
    protected function readUserFromSession()
483
    {
484
        $key = $this->createUserKey();
485
486
        if (!$this->session->has($key)) {
487
            return null;
488
        }
489
490
        return $this->session->get($key);
491
    }
492
493
    /**
494
     * @param \Generated\Shared\Transfer\UserTransfer $user
495
     *
496
     * @return bool
497
     */
498
    public function isSystemUser(UserTransfer $user)
499
    {
500
        $systemUsers = $this->userConfig->getSystemUsers();
501
502
        return in_array($user->getUsername(), $systemUsers);
503
    }
504
505
    /**
506
     * @return \Generated\Shared\Transfer\CollectionTransfer
507
     */
508
    public function getSystemUsers()
509
    {
510
        $systemUser = $this->userConfig->getSystemUsers();
511
        $collection = new CollectionTransfer();
512
513
        foreach ($systemUser as $username) {
514
            $transferUser = new UserTransfer();
515
516
            // TODO why setting the id? why is everything the username?
517
            $transferUser->setIdUser(0);
518
519
            $transferUser->setFirstName($username)
520
                ->setLastName($username)
521
                ->setUsername($username)
522
                ->setPassword($username);
523
524
            $collection->addUser($transferUser);
525
        }
526
527
        return $collection;
528
    }
529
530
    /**
531
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
532
     *
533
     * @return \Generated\Shared\Transfer\UserTransfer
534
     */
535
    public function getCurrentUser()
536
    {
537
        $user = $this->readUserFromSession();
538
539
        if ($user === null) {
540
            throw new UserNotFoundException();
541
        }
542
543
        return clone $user;
544
    }
545
546
    /**
547
     * @param \Orm\Zed\User\Persistence\SpyUser $userEntity
548
     *
549
     * @return \Generated\Shared\Transfer\UserTransfer
550
     */
551
    protected function entityToTransfer(SpyUser $userEntity)
552
    {
553
        $userTransfer = new UserTransfer();
554
        $userTransfer->fromArray($userEntity->toArray(), true);
555
556
        $userTransfer = $this->executeUserExpanderPlugins($userTransfer);
557
        $userTransfer = $this->executeUserTransferExpanderPlugins($userTransfer);
558
559
        return $userTransfer;
560
    }
561
562
    /**
563
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
564
     *
565
     * @return \Generated\Shared\Transfer\UserTransfer
566
     */
567
    protected function executeUserExpanderPlugins(UserTransfer $userTransfer): UserTransfer
568
    {
569
        $userCollectionTransfer = (new UserCollectionTransfer())->addUser($userTransfer);
570
        foreach ($this->userExpanderPlugins as $userExpanderPlugin) {
571
            $userCollectionTransfer = $userExpanderPlugin->expand($userCollectionTransfer);
572
        }
573
574
        return $userCollectionTransfer->getUsers()->getIterator()->current();
575
    }
576
577
    /**
578
     * @deprecated Use {@link \Spryker\Zed\User\Business\Model\User::executeUserExpanderPlugins()} instead.
579
     *
580
     * @param \Generated\Shared\Transfer\UserTransfer $userTransfer
581
     *
582
     * @return \Generated\Shared\Transfer\UserTransfer
583
     */
584
    protected function executeUserTransferExpanderPlugins(UserTransfer $userTransfer): UserTransfer
585
    {
586
        foreach ($this->userTransferExpanderPlugins as $userTransferExpanderPlugin) {
587
            $userTransfer = $userTransferExpanderPlugin->expandUserTransfer($userTransfer);
588
        }
589
590
        return $userTransfer;
591
    }
592
593
    /**
594
     * @param int $idUser
595
     *
596
     * @return bool
597
     */
598
    public function activateUser($idUser)
599
    {
600
        $userEntity = $this->queryUserById($idUser);
601
        $userEntity->setStatus(SpyUserTableMap::COL_STATUS_ACTIVE);
602
        $rowsAffected = $userEntity->save();
603
604
        if ($this->userConfig->isPostSavePluginsEnabledAfterUserStatusChange()) {
605
            $userTransfer = $this->entityToTransfer($userEntity);
606
            $this->executePostSavePlugins($userTransfer);
607
        }
608
609
        return $rowsAffected > 0;
610
    }
611
612
    /**
613
     * @param int $idUser
614
     *
615
     * @return bool
616
     */
617
    public function deactivateUser($idUser)
618
    {
619
        $userEntity = $this->queryUserById($idUser);
620
        $userEntity->setStatus(SpyUserTableMap::COL_STATUS_BLOCKED);
621
        $rowsAffected = $userEntity->save();
622
623
        if ($this->userConfig->isPostSavePluginsEnabledAfterUserStatusChange()) {
624
            $userTransfer = $this->entityToTransfer($userEntity);
625
            $this->executePostSavePlugins($userTransfer);
626
        }
627
628
        return $rowsAffected > 0;
629
    }
630
631
    /**
632
     * @param int $idUser
633
     *
634
     * @throws \Spryker\Zed\User\Business\Exception\UserNotFoundException
635
     *
636
     * @return \Orm\Zed\User\Persistence\SpyUser
637
     */
638
    protected function queryUserById(int $idUser): SpyUser
639
    {
640
        $userEntity = $this->queryContainer->queryUserById($idUser)->findOne();
641
        if (!$userEntity) {
642
            throw new UserNotFoundException();
643
        }
644
645
        return $userEntity;
646
    }
647
648
    /**
649
     * @return string
650
     */
651
    protected function createUserKey()
652
    {
653
        return sprintf('%s:currentUser', static::USER_BUNDLE_SESSION_KEY);
654
    }
655
}
656