Completed
Push — master ( 030030...90a95a )
by Matze
10:56 queued 07:21
created

DatabaseUserProvider::loadUserById()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 6
Bugs 0 Features 2
Metric Value
c 6
b 0
f 2
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace BrainExe\Core\Authentication;
4
5
use BrainExe\Annotations\Annotations\Inject;
6
use BrainExe\Annotations\Annotations\Service;
7
use BrainExe\Core\Authentication\Event\DeleteUserEvent;
8
use BrainExe\Core\Authentication\Exception\UsernameNotFoundException;
9
use BrainExe\Core\Traits\EventDispatcherTrait;
10
use BrainExe\Core\Traits\IdGeneratorTrait;
11
use BrainExe\Core\Traits\RedisTrait;
12
13
/**
14
 * @api
15
 * @Service(public=false)
16
 */
17
class DatabaseUserProvider
18
{
19
20
    use RedisTrait;
21
    use IdGeneratorTrait;
22
    use EventDispatcherTrait;
23
24
    const REDIS_USER       = 'user:%d';
25
    const REDIS_USER_NAMES = 'user_names';
26
27
    /**
28
     * @var PasswordHasher
29
     */
30
    private $hasher;
31
32
    /**
33
     * @var LoadUser
34
     */
35
    private $loadUser;
36
37
    /**
38
     * @Inject({
39
        "@PasswordHasher",
40
        "@Authentication.LoadUser",
41
     * })
42
     * @param PasswordHasher $passwordHasher
43
     * @param LoadUser $loadUser
44
     */
45 13
    public function __construct(PasswordHasher $passwordHasher, LoadUser $loadUser)
46
    {
47 13
        $this->hasher   = $passwordHasher;
48 13
        $this->loadUser = $loadUser;
49 13
    }
50
51
    /**
52
     * @param string $username
53
     * @return UserVO
54
     * @deprecated use LoadUser
55
     * @throws UsernameNotFoundException
56
     */
57 1
    public function loadUserByUsername($username)
58
    {
59 1
        return $this->loadUser->loadUserByUsername($username);
60
    }
61
62
    /**
63
     * @param integer $userId
64
     * @return UserVO
65
     */
66 1
    public function loadUserById($userId)
67
    {
68 1
        return $this->loadUser->loadUserById($userId);
69
    }
70
71
    /**
72
     * @return string[]
73
     */
74 1
    public function getAllUserNames()
75
    {
76 1
        return $this->getRedis()->hGetAll(self::REDIS_USER_NAMES);
1 ignored issue
show
Documentation Bug introduced by
The method hGetAll does not exist on object<BrainExe\Core\Redis\Predis>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
77
    }
78
79
    /**
80
     * @param string $password
81
     * @return string $hash
82
     */
83 3
    public function generateHash($password)
84
    {
85 3
        return $this->hasher->generateHash($password);
86
    }
87
88
    /**
89
     * @param string $password
90
     * @param string $hash
91
     * @return boolean
92
     */
93 1
    public function verifyHash($password, $hash)
94
    {
95 1
        return $this->hasher->verifyHash($password, $hash);
96
    }
97
98
    /**
99
     * @param UserVO $user
100
     * @param string $newPassword
101
     */
102 1
    public function changePassword(UserVO $user, $newPassword)
103
    {
104 1
        $hash           = $this->generateHash($newPassword);
105 1
        $user->password = $hash;
106
107 1
        $this->setUserProperty($user, 'password');
108 1
    }
109
110
    /**
111
     * @param UserVO $userVo
112
     * @param string $property
113
     */
114 3
    public function setUserProperty(UserVO $userVo, $property)
115
    {
116 3
        $redis = $this->getRedis();
117 3
        $value = $userVo->$property;
118
119 3
        if (is_array($value)) {
120 1
            $value = implode(',', $value);
121
        }
122 3
        $redis->HSET($this->getKey($userVo->id), $property, $value);
1 ignored issue
show
Documentation Bug introduced by
The method HSET does not exist on object<BrainExe\Core\Redis\Predis>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
123 3
    }
124
125
    /**
126
     * @param UserVO $user
127
     * @return integer $user_id
128
     */
129 1
    public function register(UserVO $user)
130
    {
131 1
        $redis        = $this->getRedis()->pipeline();
132 1
        $passwordHash = $this->generateHash($user->password);
133
134
        $userArray = [
135 1
            'username' => $user->getUsername(),
136 1
            'password' => $passwordHash,
137 1
            'roles'    => implode(',', $user->roles),
138 1
            'one_time_secret' => $user->one_time_secret,
139 1
            'avatar'   => $user->avatar
140
        ];
141
142 1
        $newUserId = $this->generateUniqueId();
143
144 1
        $redis->HSET(self::REDIS_USER_NAMES, strtolower($user->getUsername()), $newUserId);
145 1
        $redis->HMSET($this->getKey($newUserId), $userArray);
146
147 1
        $redis->execute();
148
149 1
        $user->id = $newUserId;
150
151 1
        return $newUserId;
152
    }
153
154
    /**
155
     * @param integer $userId
156
     */
157 2
    public function deleteUser($userId)
158
    {
159 2
        $user = $this->loadUser->loadUserById($userId);
160
161 2
        if ($user instanceof AnonymusUserVO) {
162 1
            return;
163
        }
164
165 1
        $event = new DeleteUserEvent($user, DeleteUserEvent::DELETE);
166 1
        $this->dispatchEvent($event);
167
168 1
        $redis = $this->getRedis();
169 1
        $redis->hdel(self::REDIS_USER_NAMES, strtolower($user->getUsername()));
1 ignored issue
show
Documentation Bug introduced by
The method hdel does not exist on object<BrainExe\Core\Redis\Predis>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
170 1
        $redis->del($this->getKey($userId));
1 ignored issue
show
Documentation Bug introduced by
The method del does not exist on object<BrainExe\Core\Redis\Predis>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
171 1
    }
172
173
    /**
174
     * @param integer $userId
175
     * @return string
176
     */
177 5
    private function getKey($userId)
178
    {
179 5
        return sprintf(self::REDIS_USER, $userId);
180
    }
181
}
182