Completed
Push — master ( 3f0815...763d36 )
by Philip
02:20
created

UserProvider::loadUserRolesViaManyToMany()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the CRUDlexUser package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CRUDlex;
13
14
use Symfony\Component\Security\Core\User\UserProviderInterface;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
17
use CRUDlex\AbstractData;
18
use CRUDlex\User;
19
20
/**
21
 * The implementation of the UserProviderInterface to work with the CRUDlex API.
22
 */
23
class UserProvider implements UserProviderInterface {
24
25
    /**
26
     * The Entity fieldname of the username.
27
     */
28
    protected $usernameField;
29
30
    /**
31
     * The fieldname of the password (hash).
32
     */
33
    protected $passwordField;
34
35
    /**
36
     * The fieldname of the password hash salt.
37
     */
38
    protected $saltField;
39
40
    /**
41
     * Holds the AbstractData instance to grab the user data from.
42
     */
43
    protected $userData;
44
45
    /**
46
     * Holds the AbstractData instance or the field of the many-to-many relationship to grab the user role data from.
47
     */
48
    protected $userRoleData;
49
50
    /**
51
     * Holds the AbstractData instance or the field of the many-to-many relationship to grab the user role data from.
52
     */
53
    protected $userRoleIdentifier;
54
55
    /**
56
     * Loads the roles of an user via an AbstractData instance.
57
     *
58
     * @param mixed $userId
59
     * the id of the user
60
     *
61
     * @return string[]
62
     * the roles of the user
63
     */
64
    protected function loadUserRolesViaData($userId) {
65
        $crudRoles = $this->userRoleIdentifier->listEntries(['user' => $userId], ['user' => '=']);
66
        $this->userRoleIdentifier->fetchReferences($crudRoles);
67
        $roles = ['ROLE_USER'];
68
        if ($crudRoles !== null) {
69
            foreach ($crudRoles as $crudRole) {
70
                $role = $crudRole->get('role');
71
                $roles[] = $role['name'];
72
            }
73
        }
74
        return $roles;
75
    }
76
77
    /**
78
     * Loads the roles of an user via a many-to-many relationship
79
     *
80
     * @param Entity $user
81
     * the id of the user
82
     *
83
     * @return string[]
84
     * the roles of the user
85
     */
86
    protected function loadUserRolesViaManyToMany($user) {
87
        $roles = ['ROLE_USER'];
88
        foreach ($user->get($this->userRoleIdentifier) as $role) {
0 ignored issues
show
Bug introduced by
It seems like $this->userRoleIdentifier can also be of type object<CRUDlex\AbstractData>; however, CRUDlex\Entity::get() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
89
            $roles[] = $role['name'];
90
        }
91
        return $roles;
92
    }
93
94
    /**
95
     * Constructor for data structures connecting users and roles via a many-to-many relationship on the user.
96
     *
97
     * @param AbstractData $userData
98
     * the AbstractData instance to grab the user data from
99
     *
100
     * @param string|AbstractData $userRoleIdentifier
101
     * the field of the many-to-many relationship to grab the user role data from or the AbstractData if its an own entity
102
     *
103
     * @param string $usernameField
104
     * the Entity fieldname of the username
105
     *
106
     * @param string $passwordField
107
     * the Entity fieldname of the password hash
108
     *
109
     * @param string $saltField
110
     * the Entity fieldname of the password hash salt
111
     */
112
    public function __construct(AbstractData $userData, $userRoleIdentifier = 'roles', $usernameField = 'username', $passwordField = 'password', $saltField = 'salt') {
113
        $this->userData = $userData;
114
        $this->userRoleIdentifier = $userRoleIdentifier;
115
        $this->usernameField = $usernameField;
116
        $this->passwordField = $passwordField;
117
        $this->saltField = $saltField;
118
    }
119
120
    /**
121
     * Loads and returns an user by username.
122
     * Throws an UsernameNotFoundException on not existing username.
123
     *
124
     * @param string $username
125
     * the username
126
     *
127
     * @return User
128
     * the loaded user
129
     */
130
    public function loadUserByUsername($username) {
131
132
        $users = $this->userData->listEntries([$this->usernameField => $username], [$this->usernameField => '='], 0, 1);
133
        if (count($users) === 0) {
134
            throw new UsernameNotFoundException();
135
        }
136
137
        $user = $users[0];
138
        $roles = is_string($this->userRoleIdentifier) ? $this->loadUserRolesViaManyToMany($user) : $this->loadUserRolesViaData($user->get('id'));
139
140
        $userObj = new User($this->usernameField, $this->passwordField, $this->saltField, $user, $roles);
141
        return $userObj;
142
    }
143
144
    /**
145
     * Reloads and returns the given user.
146
     * Throws an UsernameNotFoundException if the user ceased to exist meanwhile.
147
     *
148
     * @param UserInterface $user
149
     * the user to reload
150
     *
151
     * @return User
152
     * the reloaded user
153
     */
154
    public function refreshUser(UserInterface $user) {
155
        $refreshedUser = $this->loadUserByUsername($user->getUsername());
156
        return $refreshedUser;
157
    }
158
159
    /**
160
     * Tests whether the given user class is supported by this UserProvider.
161
     *
162
     * @param string $class
163
     * the user class name to test
164
     *
165
     * @return boolean
166
     * true if the class is "CRUDlex\User"
167
     */
168
    public function supportsClass($class) {
169
        return $class === 'CRUDlex\User';
170
    }
171
172
}
173