Passed
Pull Request — master (#24)
by Alexander
03:36 queued 33s
created

CurrentIdentityService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\User\CurrentIdentity;
6
7
use Psr\EventDispatcher\EventDispatcherInterface;
8
use Yiisoft\Auth\IdentityInterface;
9
use Yiisoft\Auth\IdentityRepositoryInterface;
10
use Yiisoft\User\CurrentIdentity\Storage\CurrentIdentityStorageInterface;
11
use Yiisoft\User\CurrentIdentity\Event\AfterLogout;
12
use Yiisoft\User\CurrentIdentity\Event\AfterLogin;
13
use Yiisoft\User\CurrentIdentity\Event\BeforeLogout;
14
use Yiisoft\User\CurrentIdentity\Event\BeforeLogin;
15
use Yiisoft\User\GuestIdentity;
16
17
/**
18
 * Maintains current identity and allows logging in and out using it.
19
 */
20
final class CurrentIdentityService
21
{
22
    private CurrentIdentityStorageInterface $currentIdentityStorage;
23
    private IdentityRepositoryInterface $identityRepository;
24
    private EventDispatcherInterface $eventDispatcher;
25
26
    private ?IdentityInterface $identity = null;
27
    private ?IdentityInterface $temporaryIdentity = null;
28
29 20
    public function __construct(
30
        CurrentIdentityStorageInterface $currentIdentityStorage,
31
        IdentityRepositoryInterface $identityRepository,
32
        EventDispatcherInterface $eventDispatcher
33
    ) {
34 20
        $this->currentIdentityStorage = $currentIdentityStorage;
35 20
        $this->identityRepository = $identityRepository;
36 20
        $this->eventDispatcher = $eventDispatcher;
37 20
    }
38
39
    /**
40
     * Returns the identity object associated with the currently logged-in user.
41
     */
42 16
    public function get(): IdentityInterface
43
    {
44 16
        $identity = $this->temporaryIdentity ?? $this->identity;
45
46 16
        if ($identity === null) {
47 11
            $identity = $this->determineIdentity();
48 11
            $this->identity = $identity;
49
        }
50
51 16
        return $identity;
52
    }
53
54 11
    private function determineIdentity(): IdentityInterface
55
    {
56 11
        $identity = null;
57
58 11
        $id = $this->currentIdentityStorage->get();
59 11
        if ($id !== null) {
60
            $identity = $this->identityRepository->findIdentity($id);
61
        }
62
63 11
        return $identity ?? new GuestIdentity();
64
    }
65
66
    /**
67
     * Returns a value indicating whether the user is a guest (not authenticated).
68
     *
69
     * @see get()
70
     *
71
     * @return bool Whether the current user is a guest.
72
     */
73 15
    public function isGuest(): bool
74
    {
75 15
        return $this->get() instanceof GuestIdentity;
76
    }
77
78
    /**
79
     * Logs in a user.
80
     *
81
     * @param IdentityInterface $identity The user identity (which should already be authenticated).
82
     *
83
     * @return bool Whether the user is logged in.
84
     */
85 8
    public function login(IdentityInterface $identity): bool
86
    {
87 8
        if ($this->beforeLogin($identity)) {
88 8
            $this->switchIdentity($identity);
89 8
            $this->afterLogin($identity);
90
        }
91 8
        return !$this->isGuest();
92
    }
93
94
    /**
95
     * This method is called before logging in a user.
96
     * The default implementation will trigger the {@see BeforeLogin} event.
97
     *
98
     * @param IdentityInterface $identity The user identity information.
99
     *
100
     * @return bool Whether the user should continue to be logged in.
101
     */
102 8
    private function beforeLogin(IdentityInterface $identity): bool
103
    {
104 8
        $event = new BeforeLogin($identity);
105 8
        $this->eventDispatcher->dispatch($event);
106 8
        return $event->isValid();
107
    }
108
109
    /**
110
     * This method is called after the user is successfully logged in.
111
     *
112
     * @param IdentityInterface $identity The user identity information.
113
     */
114 8
    private function afterLogin(IdentityInterface $identity): void
115
    {
116 8
        $this->eventDispatcher->dispatch(new AfterLogin($identity));
117 8
    }
118
119
    /**
120
     * Logs out the current user.
121
     *
122
     * @return bool Whether the user is logged out.
123
     */
124 3
    public function logout(): bool
125
    {
126 3
        if ($this->isGuest()) {
127 1
            return false;
128
        }
129
130 2
        $identity = $this->get();
131 2
        if ($this->beforeLogout($identity)) {
132 2
            $this->switchIdentity(new GuestIdentity());
133 2
            $this->afterLogout($identity);
134
        }
135
136 2
        return $this->isGuest();
137
    }
138
139
    /**
140
     * This method is invoked when calling {@see logout()} to log out a user.
141
     *
142
     * @param IdentityInterface $identity The user identity information.
143
     *
144
     * @return bool Whether the user should continue to be logged out.
145
     */
146 2
    private function beforeLogout(IdentityInterface $identity): bool
147
    {
148 2
        $event = new BeforeLogout($identity);
149 2
        $this->eventDispatcher->dispatch($event);
150 2
        return $event->isValid();
151
    }
152
153
    /**
154
     * This method is invoked right after a user is logged out via {@see logout()}.
155
     *
156
     * @param IdentityInterface $identity The user identity information.
157
     */
158 2
    private function afterLogout(IdentityInterface $identity): void
159
    {
160 2
        $this->eventDispatcher->dispatch(new AfterLogout($identity));
161 2
    }
162
163
    public function setTemporaryIdentity(IdentityInterface $identity): void
164
    {
165
        $this->temporaryIdentity = $identity;
166
    }
167
168
    public function clearTemporaryIdentity(): void
169
    {
170
        $this->temporaryIdentity = null;
171
    }
172
173
    /**
174
     * Switches to a new identity for the current user.
175
     *
176
     * This method is called by {@see login()} and {@see logout()}
177
     * when the current user needs to be associated with the corresponding identity information.
178
     *
179
     * @param IdentityInterface $identity The identity information to be associated with the current user.
180
     * In order to indicate that the user is guest, use {@see GuestIdentity}.
181
     */
182 8
    private function switchIdentity(IdentityInterface $identity): void
183
    {
184 8
        $this->identity = $identity;
185
186 8
        $id = $identity->getId();
187 8
        if ($id === null) {
188 2
            $this->currentIdentityStorage->clear();
189
        } else {
190 8
            $this->currentIdentityStorage->set($id);
191
        }
192 8
    }
193
}
194