Completed
Branch master (3a823b)
by Derek Stephen
04:04 queued 02:12
created

UserService::createFromArray()   B

Complexity

Conditions 8
Paths 128

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
ccs 11
cts 11
cp 1
rs 7
cc 8
eloc 11
nc 128
nop 1
crap 8
1
<?php
2
3
namespace Del\Service;
4
5
use DateTime;
6
use Del\Criteria\UserCriteria;
7
use Del\Entity\EmailLink;
8
use Del\Person\Entity\Person;
9
use Del\Entity\User;
10
use Del\Exception\EmailLinkException;
11
use Del\Exception\UserException;
12
use Del\Repository\UserRepository;
13
use Del\Person\Service\PersonService;
14
use Del\Value\User\State;
15
use Doctrine\ORM\EntityManager;
16
use InvalidArgumentException;
17
use Pimple\Container;
18
use Zend\Crypt\Password\Bcrypt;
19
20
class UserService
21
{
22
    /** @var EntityManager $em */
23
    protected $em;
24
25
    /** @var  PersonService */
26
    private $personSvc;
27
28 22
    public function __construct(Container $c)
29
    {
30 22
        $this->em = $c['doctrine.entity_manager'];
31 22
        $this->personSvc = $c['service.person'];
32 22
    }
33
34
   /** 
35
    * @param array $data
36
    * @return User
37
    */
38 16
    public function createFromArray(array $data)
39
    {
40 16
        $user = new User();
41 16
        $person = isset($data['person']) ? $data['person'] : new Person();
42 16
        $user->setPerson($person);
43 16
        isset($data['id']) ? $user->setId($data['id']) : null;
44 16
        isset($data['email']) ? $user->setEmail($data['email']) : null;
45 16
        isset($data['password']) ? $user->setPassword($data['password']) : null;
46 16
        isset($data['state']) ? $user->setState(new State($data['state'])) : null;
47 16
        isset($data['registrationDate']) ? $user->setRegistrationDate(new DateTime($data['registrationDate'])) : null;
48 16
        isset($data['lastLogin']) ? $user->setLastLogin(new DateTime($data['lastLogin'])) : null;
49 16
        return $user;
50
    }
51
52
53
54
55
    /**
56
     * @return array
57
     */
58 1
    public function toArray(User $user)
59
    {
60
        return array
61
        (
62 1
            'id' => $user->getID(),
63 1
            'email' => $user->getEmail(),
64 1
            'person' => $user->getPerson(),
65 1
            'password' => $user->getPassword(),
66 1
            'state' => $user->getState()->getValue(),
67 1
            'registrationDate' => is_null($user->getRegistrationDate()) ? null : $user->getRegistrationDate()->format('Y-m-d H:i:s'),
68 1
            'lastLoginDate' => is_null($user->getLastLoginDate()) ? null : $user->getLastLoginDate()->format('Y-m-d H:i:s'),
69 1
        );
70
    }
71
72
    /**
73
     * @param User $user
74
     * @return User
75
     */
76 16
    public function saveUser(User $user)
77 1
    {
78
//        $this->personSvc->savePerson($user->getPerson());
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
79 16
        return $this->getUserRepository()->save($user);
80
    }
81
82
    /**
83
     * @param int $id
84
     * @return User|null
85
     */
86 1 View Code Duplication
    public function findUserById($id)
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...
87
    {
88 1
        $criteria = new UserCriteria();
89 1
        $criteria->setId($id);
90 1
        $results = $this->getUserRepository()->findByCriteria($criteria);
91 1
        return (count($results)) ? $results[0] : null;
92
    }
93
94
    /**
95
     * @param string $email
96
     * @return User|null
97
     */
98 1 View Code Duplication
    public function findUserByEmail($email)
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...
99
    {
100 1
        $criteria = new UserCriteria();
101 1
        $criteria->setEmail($email);
102 1
        $result = $this->getUserRepository()->findByCriteria($criteria);
103 1
        return count($result) ? $result[0] : null;
104
    }
105
106
   /**
107
    * @return UserRepository
108
    */
109 17
    private function getUserRepository()
110
    {
111 17
        return $this->em->getRepository('Del\Entity\User');
112
    }
113
114
    /**
115
     * @return \Del\Repository\EmailLink
116
     */
117 5
    private function getEmailLinkRepository()
118
    {
119 5
        return $this->em->getRepository('Del\Entity\EmailLink');
120
    }
121
122 4
    public function registerUser(array $data)
123
    {
124 4
        if (!isset($data['email']) || !isset($data['password']) || !isset($data['confirm'])) {
125 1
            throw new InvalidArgumentException();
126
        }
127 3
        if ($data['password'] !== $data['confirm']) {
128 1
            throw new UserException(UserException::WRONG_PASSWORD);
129
        }
130
131 2
        $criteria = new UserCriteria();
132 2
        $criteria->setEmail($data['email']);
133 2
        $user = $this->getUserRepository()->findByCriteria($criteria);
134 2
        if(!empty($user)) {
135 1
            throw new UserException(UserException::USER_EXISTS);
136
        }
137
138 2
        $person = new Person();
139 2
        $user = new User();
140 2
        $state = new State(State::STATE_UNACTIVATED);
141 2
        $user->setPerson($person)
142 2
             ->setEmail($data['email'])
143 2
             ->setRegistrationDate(new DateTime())
144 2
             ->setState($state);
145
146 2
        $bcrypt = new Bcrypt();
147 2
        $bcrypt->setCost(14);
148
149 2
        $encryptedPassword = $bcrypt->create($data['password']);
150 2
        $user->setPassword($encryptedPassword);
151
152 2
        $this->saveUser($user);
153 2
        return $user;
154
    }
155
156
    /**
157
     * @param User $user
158
     * @param $password
159
     * @return User
160
     */
161 6
    public function changePassword(User $user, $password)
162
    {
163 6
        $bcrypt = new Bcrypt();
164 6
        $bcrypt->setCost(14);
165
166 6
        $encryptedPassword = $bcrypt->create($password);
167 6
        $user->setPassword($encryptedPassword);
168
169 6
        $this->saveUser($user);
170 6
        return $user;
171
    }
172
173
    /**
174
     * @param User $user
175
     * @param int $expiry_days
176
     * @return EmailLink
177
     */
178 4
    public function generateEmailLink(User $user, $expiry_days = 7)
179
    {
180 4
        $date = new DateTime();
181 4
        $date->modify('+'.$expiry_days.' days');
182 4
        $token = md5(uniqid(rand(), true));
183 4
        $link = new EmailLink();
184 4
        $link->setUser($user);
185 4
        $link->setToken($token);
186 4
        $link->setExpiryDate($date);
187 4
        return $this->getEmailLinkRepository()->save($link);
188
    }
189
190
    /**
191
     * @param EmailLink $link
192
     */
193 4
    public function deleteEmailLink(EmailLink $link)
194
    {
195
        /** @var EmailLink $link */
196 4
        $link = $this->em->merge($link);
197 4
        $this->getEmailLinkRepository()->delete($link);
198 4
    }
199
200
    /**
201
     * @param User $user
202
     */
203 16
    public function deleteUser(User $user, $deletePerson = false)
204
    {
205 16
        $this->getUserRepository()->delete($user,$deletePerson);
206 16
    }
207
208
    /**
209
     * @param $email
210
     * @param $token
211
     * @return EmailLink
212
     * @throws EmailLinkException
213
     */
214 4
    public function findEmailLink($email, $token)
215
    {
216 4
        $link = $this->getEmailLinkRepository()->findByToken($token);
217 4
        if(!$link) {
218 1
            throw new EmailLinkException(EmailLinkException::LINK_NOT_FOUND);
219
        }
220 3
        if($link->getUser()->getEmail() != $email) {
221 1
            throw new EmailLinkException(EmailLinkException::LINK_NO_MATCH);
222
        }
223 2
        if($link->getExpiryDate() < new DateTime()) {
224 1
            throw new EmailLinkException(EmailLinkException::LINK_EXPIRED);
225
        }
226 1
        return $link;
227
    }
228
229
    /**
230
     * @param string $email
231
     * @param string $password
232
     * @return int
233
     * @throws UserException
234
     */
235 6
    function authenticate($email, $password)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
236
    {
237 6
        $criteria = new UserCriteria();
238 6
        $criteria->setEmail($email);
239
240 6
        $user = $this->getUserRepository()->findByCriteria($criteria);
241
242 6
        if(empty($user)) {
243 1
            throw new UserException(UserException::USER_NOT_FOUND);
244
        }
245
246
        /** @var User $user  */
247 5
        $user = $user[0];
248
249 5
        switch($user->getState()->getValue()) {
250 5
            case State::STATE_UNACTIVATED :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
251 1
                throw new UserException(UserException::USER_UNACTIVATED);
252
                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...
253 4
            case State::STATE_DISABLED :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
254 4
            case State::STATE_SUSPENDED :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
255 1
                throw new UserException(UserException::USER_DISABLED);
256
                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...
257 3
            case State::STATE_BANNED :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
258 1
                throw new UserException(UserException::USER_BANNED);
259
                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...
260
261 2
        }
262
263 2
        $bcrypt = new Bcrypt();
264 2
        $bcrypt->setCost(14);
265
266 2
        if(!$bcrypt->verify($password, $user->getPassword()))
267 2
        {
268 1
            throw new UserException(UserException::WRONG_PASSWORD);
269
        }
270
271 1
        return $user->getID();
272
    }
273
274
    /**
275
     * @param UserCriteria $criteria
276
     * @return array
277
     */
278 1
    public function findByCriteria(UserCriteria $criteria)
279
    {
280 1
        return $this->getUserRepository()->findByCriteria($criteria);
281
    }
282
283
    /**
284
     * @param User $user
285
     * @param $password
286
     * @return bool
287
     */
288 1
    public function checkPassword(User $user, $password)
289
    {
290 1
        $bcrypt = new Bcrypt();
291 1
        $bcrypt->setCost(14);
292
293 1
        return $bcrypt->verify($password, $user->getPassword());
294
    }
295
296
}