Passed
Pull Request — master (#24)
by Sergei
02:14 queued 13s
created

CurrentUser::beforeLogout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\User;
6
7
use Psr\EventDispatcher\EventDispatcherInterface;
8
use Yiisoft\Access\AccessCheckerInterface;
9
use Yiisoft\Auth\IdentityInterface;
10
use Yiisoft\Auth\IdentityRepositoryInterface;
11
use Yiisoft\User\CurrentIdentityStorage\CurrentIdentityStorageInterface;
12
use Yiisoft\User\Event\AfterLogout;
13
use Yiisoft\User\Event\AfterLogin;
14
use Yiisoft\User\Event\BeforeLogout;
15
use Yiisoft\User\Event\BeforeLogin;
16
17
final class CurrentUser
18
{
19
    private CurrentIdentityStorageInterface $currentIdentityStorage;
20
    private IdentityRepositoryInterface $identityRepository;
21
    private EventDispatcherInterface $eventDispatcher;
22
23
    private ?AccessCheckerInterface $accessChecker = null;
24
25
    private ?IdentityInterface $identity = null;
26
    private ?IdentityInterface $temporarilyIdentity = null;
27
28 22
    public function __construct(
29
        CurrentIdentityStorageInterface $currentIdentityStorage,
30
        IdentityRepositoryInterface $identityRepository,
31
        EventDispatcherInterface $eventDispatcher
32
    ) {
33 22
        $this->currentIdentityStorage = $currentIdentityStorage;
34 22
        $this->identityRepository = $identityRepository;
35 22
        $this->eventDispatcher = $eventDispatcher;
36 22
    }
37
38 1
    public function setAccessChecker(AccessCheckerInterface $accessChecker): void
39
    {
40 1
        $this->accessChecker = $accessChecker;
41 1
    }
42
43
    /**
44
     * Returns the identity object associated with the currently logged-in user.
45
     */
46 17
    public function getIdentity(): IdentityInterface
47
    {
48 17
        $identity = $this->temporarilyIdentity ?? $this->identity;
49
50 17
        if ($identity === null) {
51 12
            $identity = $this->determineIdentity();
52 12
            $this->identity = $identity;
53
        }
54
55 17
        return $identity;
56
    }
57
58 12
    private function determineIdentity(): IdentityInterface
59
    {
60 12
        $identity = null;
61
62 12
        $id = $this->currentIdentityStorage->get();
63 12
        if ($id !== null) {
64
            $identity = $this->identityRepository->findIdentity($id);
65
        }
66
67 12
        return $identity ?? new GuestIdentity();
68
    }
69
70
    /**
71
     * Returns a value that uniquely represents the user.
72
     *
73
     * @see getIdentity()
74
     *
75
     * @return string The unique identifier for the user. If `null`, it means the user is a guest.
76
     */
77 4
    public function getId(): ?string
78
    {
79 4
        return $this->getIdentity()->getId();
80
    }
81
82
    /**
83
     * Returns a value indicating whether the user is a guest (not authenticated).
84
     *
85
     * @see getIdentity()
86
     *
87
     * @return bool Whether the current user is a guest.
88
     */
89 15
    public function isGuest(): bool
90
    {
91 15
        return $this->getIdentity() instanceof GuestIdentity;
92
    }
93
94
    /**
95
     * Checks if the user can perform the operation as specified by the given permission.
96
     *
97
     * Note that you must provide access checker via {@see CurrentUser::setAccessChecker()} in order
98
     * to use this method. Otherwise it will always return false.
99
     *
100
     * @param string $permissionName The name of the permission (e.g. "edit post") that needs access check.
101
     * @param array $params Name-value pairs that would be passed to the rules associated
102
     * with the roles and permissions assigned to the user.
103
     *
104
     * @return bool Whether the user can perform the operation as specified by the given permission.
105
     */
106 2
    public function can(string $permissionName, array $params = []): bool
107
    {
108 2
        if ($this->accessChecker === null) {
109 1
            return false;
110
        }
111
112 1
        return $this->accessChecker->userHasPermission($this->getId(), $permissionName, $params);
113
    }
114
115
    /**
116
     * Logs in a user.
117
     *
118
     * @param IdentityInterface $identity The user identity (which should already be authenticated).
119
     *
120
     * @return bool Whether the user is logged in.
121
     */
122 8
    public function login(IdentityInterface $identity): bool
123
    {
124 8
        if ($this->beforeLogin($identity)) {
125 8
            $this->switchIdentity($identity);
126 8
            $this->afterLogin($identity);
127
        }
128 8
        return !$this->isGuest();
129
    }
130
131
    /**
132
     * This method is called before logging in a user.
133
     * The default implementation will trigger the {@see BeforeLogin} event.
134
     *
135
     * @param IdentityInterface $identity The user identity information.
136
     *
137
     * @return bool Whether the user should continue to be logged in.
138
     */
139 8
    private function beforeLogin(IdentityInterface $identity): bool
140
    {
141 8
        $event = new BeforeLogin($identity);
142 8
        $this->eventDispatcher->dispatch($event);
143 8
        return $event->isValid();
144
    }
145
146
    /**
147
     * This method is called after the user is successfully logged in.
148
     *
149
     * @param IdentityInterface $identity The user identity information.
150
     */
151 8
    private function afterLogin(IdentityInterface $identity): void
152
    {
153 8
        $this->eventDispatcher->dispatch(new AfterLogin($identity));
154 8
    }
155
156
    /**
157
     * Logs out the current user.
158
     *
159
     * @return bool Whether the user is logged out.
160
     */
161 3
    public function logout(): bool
162
    {
163 3
        if ($this->isGuest()) {
164 1
            return false;
165
        }
166
167 2
        $identity = $this->getIdentity();
168 2
        if ($this->beforeLogout($identity)) {
169 2
            $this->switchIdentity(new GuestIdentity());
170 2
            $this->afterLogout($identity);
171
        }
172
173 2
        return $this->isGuest();
174
    }
175
176
    /**
177
     * This method is invoked when calling {@see logout()} to log out a user.
178
     *
179
     * @param IdentityInterface $identity The user identity information.
180
     *
181
     * @return bool Whether the user should continue to be logged out.
182
     */
183 2
    private function beforeLogout(IdentityInterface $identity): bool
184
    {
185 2
        $event = new BeforeLogout($identity);
186 2
        $this->eventDispatcher->dispatch($event);
187 2
        return $event->isValid();
188
    }
189
190
    /**
191
     * This method is invoked right after a user is logged out via {@see logout()}.
192
     *
193
     * @param IdentityInterface $identity The user identity information.
194
     */
195 2
    private function afterLogout(IdentityInterface $identity): void
196
    {
197 2
        $this->eventDispatcher->dispatch(new AfterLogout($identity));
198 2
    }
199
200
    public function setTemporarilyIdentity(IdentityInterface $identity): void
201
    {
202
        $this->temporarilyIdentity = $identity;
203
    }
204
205
    public function clearTemporarilyIdentity(): void
206
    {
207
        $this->temporarilyIdentity = null;
208
    }
209
210
    /**
211
     * Switches to a new identity for the current user.
212
     *
213
     * This method is called by {@see login()} and {@see logout()}
214
     * when the current user needs to be associated with the corresponding identity information.
215
     *
216
     * @param IdentityInterface $identity The identity information to be associated with the current user.
217
     * In order to indicate that the user is guest, use {@see GuestIdentity}.
218
     */
219 8
    private function switchIdentity(IdentityInterface $identity): void
220
    {
221 8
        $this->identity = $identity;
222
223 8
        $id = $identity->getId();
224 8
        if ($id === null) {
225 2
            $this->currentIdentityStorage->clear();
226
        } else {
227 8
            $this->currentIdentityStorage->set($id);
228
        }
229 8
    }
230
}
231