Passed
Push — master ( 1d30f9...202808 )
by Peter
04:48
created

TokenSqlDataMapper::update()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 28
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 28
rs 9.6333
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Admin\Orm\DataMappers;
6
7
use AbterPhp\Admin\Domain\Entities\Token as Entity;
8
use Opulence\Orm\DataMappers\SqlDataMapper;
9
use Opulence\QueryBuilders\MySql\QueryBuilder;
10
use Opulence\QueryBuilders\MySql\SelectQuery;
11
12
class TokenSqlDataMapper extends SqlDataMapper implements IUserDataMapper
13
{
14
    use IdGeneratorUserTrait;
0 ignored issues
show
Bug introduced by
The type AbterPhp\Admin\Orm\DataM...rs\IdGeneratorUserTrait 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...
15
16
    /**
17
     * @param Entity $entity
18
     */
19
    public function add($entity)
20
    {
21
        if (!($entity instanceof Entity)) {
0 ignored issues
show
introduced by
$entity is always a sub-type of AbterPhp\Admin\Domain\Entities\Token.
Loading history...
22
            throw new \InvalidArgumentException(__CLASS__ . ':' . __FUNCTION__ . ' expects a User entity.');
23
        }
24
25
        $query = (new QueryBuilder())
26
            ->insert(
27
                'users',
28
                [
29
                    'id'                  => [$entity->getId(), \PDO::PARAM_STR],
30
                    'username'            => [$entity->getUsername(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getUsername() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

30
                    'username'            => [$entity->/** @scrutinizer ignore-call */ getUsername(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
31
                    'email'               => [$entity->getEmail(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getEmail() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

31
                    'email'               => [$entity->/** @scrutinizer ignore-call */ getEmail(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
32
                    'password'            => [$entity->getPassword(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getPassword() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
                    'password'            => [$entity->/** @scrutinizer ignore-call */ getPassword(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
33
                    'user_language_id'    => [$entity->getUserLanguage()->getId(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getUserLanguage() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

33
                    'user_language_id'    => [$entity->/** @scrutinizer ignore-call */ getUserLanguage()->getId(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
34
                    'can_login'           => [$entity->canLogin(), \PDO::PARAM_INT],
0 ignored issues
show
Bug introduced by
The method canLogin() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

34
                    'can_login'           => [$entity->/** @scrutinizer ignore-call */ canLogin(), \PDO::PARAM_INT],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
35
                    'is_gravatar_allowed' => [$entity->isGravatarAllowed(), \PDO::PARAM_INT],
0 ignored issues
show
Bug introduced by
The method isGravatarAllowed() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

35
                    'is_gravatar_allowed' => [$entity->/** @scrutinizer ignore-call */ isGravatarAllowed(), \PDO::PARAM_INT],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
36
                ]
37
            );
38
39
        $statement = $this->writeConnection->prepare($query->getSql());
40
        $statement->bindValues($query->getParameters());
41
        $statement->execute();
42
43
        $this->addUserGroups($entity);
44
    }
45
46
    /**
47
     * @param Entity $entity
48
     */
49
    public function delete($entity)
50
    {
51
        if (!($entity instanceof Entity)) {
0 ignored issues
show
introduced by
$entity is always a sub-type of AbterPhp\Admin\Domain\Entities\Token.
Loading history...
52
            throw new \InvalidArgumentException(__CLASS__ . ':' . __FUNCTION__ . ' expects a User entity.');
53
        }
54
55
        $rand     = rand(0, PHP_INT_MAX);
56
        $username = sprintf('deleted-%d', $rand);
57
58
        $this->deleteUserGroups($entity);
59
60
        $query = (new QueryBuilder())
61
            ->update(
62
                'users',
63
                'users',
64
                [
65
                    'deleted'  => [1, \PDO::PARAM_INT],
66
                    'email'    => [sprintf('%[email protected]', $username), \PDO::PARAM_STR],
67
                    'username' => [$username, \PDO::PARAM_STR],
68
                    'password' => ['', \PDO::PARAM_STR],
69
                ]
70
            )
71
            ->where('id = ?')
72
            ->addUnnamedPlaceholderValue($entity->getId(), \PDO::PARAM_STR);
73
74
        $statement = $this->writeConnection->prepare($query->getSql());
75
        $statement->bindValues($query->getParameters());
76
        $statement->execute();
77
    }
78
79
    /**
80
     * @return Entity[]
81
     */
82
    public function getAll(): array
83
    {
84
        $query = $this->getBaseQuery();
85
86
        $sql = $query->getSql();
87
88
        return $this->read($sql, [], self::VALUE_TYPE_ARRAY);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->read($sql,...self::VALUE_TYPE_ARRAY) could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
89
    }
90
91
    /**
92
     * @param int|string $id
93
     *
94
     * @return Entity|null
95
     */
96
    public function getById($id): ?Entity
97
    {
98
        $query = $this->getBaseQuery()->andWhere('users.id = :user_id');
99
100
        $sql    = $query->getSql();
101
        $params = ['user_id' => [$id, \PDO::PARAM_STR]];
102
103
        return $this->read($sql, $params, self::VALUE_TYPE_ENTITY, true);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->read($sql,...ALUE_TYPE_ENTITY, true) could return the type array which is incompatible with the type-hinted return AbterPhp\Admin\Domain\Entities\Token|null. Consider adding an additional type-check to rule them out.
Loading history...
104
    }
105
106
    /**
107
     * @param string $clientId
108
     *
109
     * @return Entity|null
110
     */
111
    public function getByClientId(string $clientId): ?Entity
112
    {
113
        $query = $this->getBaseQuery()->andWhere('`api_client_id` = :api_client_id');
114
115
        $sql    = $query->getSql();
116
        $params = ['api_client_id' => [$clientId, \PDO::PARAM_STR]];
117
118
        return $this->read($sql, $params, self::VALUE_TYPE_ENTITY, true);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->read($sql,...ALUE_TYPE_ENTITY, true) could return the type array which is incompatible with the type-hinted return AbterPhp\Admin\Domain\Entities\Token|null. Consider adding an additional type-check to rule them out.
Loading history...
119
    }
120
121
    /**
122
     * @param Entity $entity
123
     */
124
    public function update($entity)
125
    {
126
        if (!($entity instanceof Entity)) {
0 ignored issues
show
introduced by
$entity is always a sub-type of AbterPhp\Admin\Domain\Entities\Token.
Loading history...
127
            throw new \InvalidArgumentException(__CLASS__ . ':' . __FUNCTION__ . ' expects a User entity.');
128
        }
129
130
        $query = (new QueryBuilder())
131
            ->update(
132
                'tokens',
133
                'tokens',
134
                [
135
                    'username'            => [$entity->getUsername(), \PDO::PARAM_STR],
136
                    'email'               => [$entity->getEmail(), \PDO::PARAM_STR],
137
                    'password'            => [$entity->getPassword(), \PDO::PARAM_STR],
138
                    'user_language_id'    => [$entity->getUserLanguage()->getId(), \PDO::PARAM_STR],
139
                    'can_login'           => [$entity->canLogin(), \PDO::PARAM_INT],
140
                    'is_gravatar_allowed' => [$entity->isGravatarAllowed(), \PDO::PARAM_INT],
141
                ]
142
            )
143
            ->where('id = ?')
144
            ->addUnnamedPlaceholderValue($entity->getId(), \PDO::PARAM_STR);
145
146
        $statement = $this->writeConnection->prepare($query->getSql());
147
        $statement->bindValues($query->getParameters());
148
        $statement->execute();
149
150
        $this->deleteUserGroups($entity);
151
        $this->addUserGroups($entity);
152
    }
153
154
    /**
155
     * @param Entity $entity
156
     * @param bool   $create
157
     *
158
     * @return array
159
     */
160
    protected function getColumnNamesToValues(Entity $entity, bool $create): array
161
    {
162
        $columnNamesToValues = [
163
            'name'       => [$entity->getName(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getName() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
            'name'       => [$entity->/** @scrutinizer ignore-call */ getName(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
            'identifier' => [$entity->getIdentifier(), \PDO::PARAM_STR],
0 ignored issues
show
Bug introduced by
The method getIdentifier() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

164
            'identifier' => [$entity->/** @scrutinizer ignore-call */ getIdentifier(), \PDO::PARAM_STR],

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
165
        ];
166
167
        if ($create) {
168
            $columnNamesToValues = array_merge(['id' => [$entity->getId(), \PDO::PARAM_STR]], $columnNamesToValues);
169
        }
170
171
        return $columnNamesToValues;
172
    }
173
174
    /**
175
     * @param array $data
176
     *
177
     * @return Entity
178
     */
179
    protected function loadEntity(array $data): Entity
180
    {
181
        if (empty($data['id'])) {
182
            throw new \RuntimeException();
183
        }
184
185
        $userLanguage = new UserLanguage(
186
            $data['user_language_id'],
187
            $data['user_language_identifier'],
188
            ''
189
        );
190
        $userGroups   = $this->loadUserGroups($data);
191
192
        return new Entity(
193
            $data['id'],
194
            $data['username'],
195
            $data['email'],
196
            $data['password'],
197
            (bool)$data['can_login'],
0 ignored issues
show
Bug introduced by
(bool)$data['can_login'] of type boolean is incompatible with the type array expected by parameter $adminResources of AbterPhp\Admin\Domain\En...es\Token::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

197
            /** @scrutinizer ignore-type */ (bool)$data['can_login'],
Loading history...
198
            (bool)$data['is_gravatar_allowed'],
0 ignored issues
show
Unused Code introduced by
The call to AbterPhp\Admin\Domain\En...es\Token::__construct() has too many arguments starting with (bool)$data['is_gravatar_allowed']. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

198
        return /** @scrutinizer ignore-call */ new Entity(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
199
            $userLanguage,
200
            $userGroups
201
        );
202
    }
203
204
    /**
205
     * @param array $data
206
     *
207
     * @return UserGroup[]
208
     */
209
    protected function loadUserGroups(array $data): array
210
    {
211
        if (empty($data['user_group_ids'])) {
212
            return [];
213
        }
214
215
        $ids         = explode(',', $data['user_group_ids']);
216
        $identifiers = explode(',', $data['user_group_identifiers']);
217
        $names       = explode(',', $data['user_group_names']);
218
219
        if (count($ids) !== count($identifiers) || count($ids) !== count($names)) {
220
            throw new \LogicException();
221
        }
222
223
        $userGroups = [];
224
        foreach ($ids as $idx => $userGroupId) {
225
            $userGroups[] = new UserGroup($userGroupId, $identifiers[$idx], $names[$idx]);
226
        }
227
228
        return $userGroups;
229
    }
230
231
    /**
232
     * @return SelectQuery
233
     */
234
    private function getBaseQuery(): SelectQuery
235
    {
236
        /** @var SelectQuery $query */
237
        $query = (new QueryBuilder())
238
            ->select(
239
                'users.id',
240
                'users.username',
241
                'users.email',
242
                'users.password',
243
                'users.user_language_id',
244
                'ul.identifier AS user_language_identifier',
245
                'users.can_login',
246
                'users.is_gravatar_allowed',
247
                'GROUP_CONCAT(ug.id) AS user_group_ids',
248
                'GROUP_CONCAT(ug.identifier) AS user_group_identifiers',
249
                'GROUP_CONCAT(ug.name) AS user_group_names'
250
            )
251
            ->from('users')
252
            ->innerJoin(
253
                'user_languages',
254
                'ul',
255
                'ul.id = users.user_language_id AND ul.deleted = 0'
256
            )
257
            ->leftJoin('users_user_groups', 'uug', 'uug.user_id = users.id AND uug.deleted = 0')
258
            ->leftJoin('user_groups', 'ug', 'ug.id = uug.user_group_id AND ug.deleted = 0')
259
            ->groupBy('users.id')
260
            ->where('users.deleted = 0');
261
262
        return $query;
263
    }
264
265
    /**
266
     * @param Entity $entity
267
     */
268
    protected function deleteUserGroups(Entity $entity)
269
    {
270
        $query = (new QueryBuilder())
271
            ->delete('users_user_groups')
272
            ->where('user_id = ?')
273
            ->addUnnamedPlaceholderValue($entity->getId(), \PDO::PARAM_STR);
274
275
        $statement = $this->writeConnection->prepare($query->getSql());
276
        $statement->bindValues($query->getParameters());
277
        $statement->execute();
278
    }
279
280
    /**
281
     * @param Entity $entity
282
     */
283
    protected function addUserGroups(Entity $entity)
284
    {
285
        $idGenerator = $this->getIdGenerator();
286
287
        foreach ($entity->getUserGroups() as $userGroup) {
0 ignored issues
show
Bug introduced by
The method getUserGroups() does not exist on AbterPhp\Admin\Domain\Entities\Token. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

287
        foreach ($entity->/** @scrutinizer ignore-call */ getUserGroups() as $userGroup) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
288
            $query = (new QueryBuilder())
289
                ->insert(
290
                    'users_user_groups',
291
                    [
292
                        'id'            => [$idGenerator->generate($entity), \PDO::PARAM_STR],
293
                        'user_id'       => [$entity->getId(), \PDO::PARAM_STR],
294
                        'user_group_id' => [$userGroup->getId(), \PDO::PARAM_STR],
295
                    ]
296
                );
297
298
            $statement = $this->writeConnection->prepare($query->getSql());
299
            $statement->bindValues($query->getParameters());
300
            $statement->execute();
301
        }
302
    }
303
}
304