Passed
Push — master ( 5a9db6...0ba8a9 )
by Melech
28:27 queued 23:54
created

InMemoryAdapter::retrieve()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Auth\Adapters;
15
16
use Valkyrja\Auth\AuthenticationAttempt;
17
use Valkyrja\Auth\AuthenticationRetrieval;
18
use Valkyrja\Auth\Exceptions\InvalidUserException;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Auth\Exceptions\InvalidUserException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Valkyrja\Auth\User;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Auth\User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
21
/**
22
 * Class InMemoryAdapter.
23
 *
24
 * @author Melech Mizrachi
25
 */
26
class InMemoryAdapter extends Adapter2
27
{
28
    public const USER_DOES_NOT_EXIST_EXCEPTION_MESSAGE = 'User does not exist.';
29
    public const USER_DOES_EXIST_EXCEPTION_MESSAGE     = 'User already exists.';
30
31
    /**
32
     * The users.
33
     *
34
     * @var User[]
35
     */
36
    protected static array $users = [];
37
38
    /**
39
     * Filter users via retrieval fields.
40
     *
41
     * @param array $retrievalFields
42
     * @param User  $user
43
     *
44
     * @return bool
45
     */
46
    protected static function filterUsers(array $retrievalFields, User $user): bool
47
    {
48
        $match = null;
49
50
        foreach ($retrievalFields as $field => $retrievalField) {
51
            $value = $user->__get($field);
52
53
            if ($match === null) {
54
                $match = $value === $retrievalField;
55
            } else {
56
                $match = $match && $value === $retrievalField;
0 ignored issues
show
introduced by
$match is of type null, thus it always evaluated to false.
Loading history...
57
            }
58
        }
59
60
        return $match;
61
    }
62
63
    /**
64
     * @inheritDoc
65
     */
66
    public function authenticate(AuthenticationAttempt $attempt): User|null
67
    {
68
        $user = $this->retrieve($attempt);
69
70
        if ($user !== null && $this->verifyUserPassword($user, $attempt->getPassword())) {
71
            return $user;
72
        }
73
74
        return null;
75
    }
76
77
    /**
78
     * @inheritDoc
79
     */
80
    public function retrieve(AuthenticationRetrieval $retrieval): User|null
81
    {
82
        $retrievalFields = $retrieval->getRetrievalFields($this->user);
83
84
        return $this->getUserViaRetrievalFields($retrievalFields);
85
    }
86
87
    /**
88
     * @inheritDoc
89
     */
90
    public function create(User $user): void
91
    {
92
        $retrievalFields = $this->getRetrievalFieldsFromUser($user);
93
        $existingUser    = $this->getUserViaRetrievalFields($retrievalFields);
94
95
        if ($existingUser !== null) {
96
            throw new InvalidUserException(self::USER_DOES_EXIST_EXCEPTION_MESSAGE);
97
        }
98
99
        static::$users[] = clone $user;
100
    }
101
102
    /**
103
     * @inheritDoc
104
     *
105
     * @throws InvalidUserException
106
     */
107
    public function save(User $user): void
108
    {
109
        $retrievalFields = $this->getRetrievalFieldsFromUser($user);
110
        $existingUser    = $this->getUserViaRetrievalFields($retrievalFields);
111
112
        if ($existingUser === null) {
113
            throw new InvalidUserException(static::USER_DOES_NOT_EXIST_EXCEPTION_MESSAGE);
114
        }
115
116
        $existingUser->updateProperties($user->asStorableChangedArray());
117
    }
118
119
    /**
120
     * Get the retrieval fields from a user object.
121
     *
122
     * @param User $user
123
     *
124
     * @return array<string, int|string>
125
     */
126
    protected function getRetrievalFieldsFromUser(User $user): array
127
    {
128
        $retrievalFields       = $user::getAuthenticationFields();
129
        $retrievalFieldsFilled = [];
130
131
        foreach ($retrievalFields as $retrievalField) {
132
            $retrievalFieldsFilled[$retrievalField] = $user->{$retrievalField};
133
        }
134
135
        return $retrievalFieldsFilled;
136
    }
137
138
    /**
139
     * Get user via retrieval fields.
140
     *
141
     * @param array $retrievalFields
142
     *
143
     * @return User|null
144
     */
145
    protected function getUserViaRetrievalFields(array $retrievalFields): User|null
146
    {
147
        $users = static::$users;
148
149
        $filteredUsers = array_filter(
150
            $users,
151
            static fn (User $user) => static::filterUsers($retrievalFields, $user)
152
        );
153
154
        return $filteredUsers[0] ?? null;
155
    }
156
}
157