Passed
Pull Request — master (#1266)
by Tarmo
07:49
created

UserRepository::loadUserByIdentifier()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 20
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 35
ccs 18
cts 18
cp 1
crap 5
rs 9.2888
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/Repository/UserRepository.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\Repository;
10
11
use App\Entity\User as Entity;
12
use App\Rest\UuidHelper;
13
use Doctrine\ORM\NonUniqueResultException;
14
use Doctrine\Persistence\ManagerRegistry;
15
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
16
use function array_key_exists;
17
18
/**
19
 * Class UserRepository
20
 *
21
 * @package App\Repository
22
 * @author TLe, Tarmo Leppänen <[email protected]>
23
 *
24
 * @psalm-suppress LessSpecificImplementedReturnType
25
 * @codingStandardsIgnoreStart
26
 *
27
 * @method Entity|null find(string $id, ?int $lockMode = null, ?int $lockVersion = null)
28
 * @method Entity|null findAdvanced(string $id, string | int | null $hydrationMode = null)
29
 * @method Entity|null findOneBy(array $criteria, ?array $orderBy = null)
30
 * @method Entity[] findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null)
31
 * @method Entity[] findByAdvanced(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null, ?array $search = null)
32
 * @method Entity[] findAll()
33
 *
34
 * @codingStandardsIgnoreEnd
35
 */
36
class UserRepository extends BaseRepository
37
{
38
    /**
39
     * @var array<int, string>
40
     */
41
    protected static array $searchColumns = ['username', 'firstName', 'lastName', 'email'];
42
43
    /**
44
     * @psalm-var class-string
45
     */
46
    protected static string $entityName = Entity::class;
47
48 576
    public function __construct(
49
        protected ManagerRegistry $managerRegistry,
50
        private string $environment,
51
    ) {
52 576
    }
53
54
    /**
55
     * Method to check if specified username is available or not.
56
     *
57
     * @throws NonUniqueResultException
58
     */
59 1
    public function isUsernameAvailable(string $username, ?string $id = null): bool
60
    {
61 1
        return $this->isUnique('username', $username, $id);
62
    }
63
64
    /**
65
     * Method to check if specified email is available or not.
66
     *
67
     * @param string $email Email to check
68
     * @param string|null $id User id to ignore
69
     *
70
     * @throws NonUniqueResultException
71
     */
72 1
    public function isEmailAvailable(string $email, ?string $id = null): bool
73
    {
74 1
        return $this->isUnique('email', $email, $id);
75
    }
76
77
    /**
78
     * Loads the user for the given username.
79
     *
80
     * This method must throw UsernameNotFoundException if the user is not found.
81
     *
82
     * Method is override for performance reasons see link below.
83
     *
84
     * @see http://symfony2-document.readthedocs.org/en/latest/cookbook/security/entity_provider.html
85
     *      #managing-roles-in-the-database
86
     *
87
     * @param string $username The username
88
     * @param bool $uuid Is username parameter UUID or not
89
     *
90
     * @throws NonUniqueResultException
91
     */
92 287
    public function loadUserByIdentifier(string $username, bool $uuid): ?Entity
93
    {
94
        /** @var array<string, Entity|null> $cache */
95 287
        static $cache = [];
96
97 287
        if (!array_key_exists($username, $cache) || $this->environment === 'test') {
98
            // Build query
99 287
            $queryBuilder = $this
100 287
                ->createQueryBuilder('u')
101 287
                ->select('u, g, r')
102 287
                ->leftJoin('u.userGroups', 'g')
103 287
                ->leftJoin('g.role', 'r');
104
105 287
            if ($uuid) {
106
                $queryBuilder
107 259
                    ->where('u.id = :uuid')
108 259
                    ->setParameter('uuid', $username, UuidBinaryOrderedTimeType::NAME);
109
            } else {
110
                $queryBuilder
111 61
                    ->where('u.username = :username OR u.email = :email')
112 61
                    ->setParameter('username', $username)
113 61
                    ->setParameter('email', $username);
114
            }
115
116 287
            $query = $queryBuilder->getQuery();
117
118
            // phpcs:disable
119
            /** @var Entity|null $result */
120 287
            $result = $query->getOneOrNullResult();
121
122 287
            $cache[$username] = $result;
123
            // phpcs:enable
124
        }
125
126 287
        return $cache[$username] instanceof Entity ? $cache[$username] : null;
127
    }
128
129
    /**
130
     * @param string $column Column to check
131
     * @param string $value Value of specified column
132
     * @param string|null $id User id to ignore
133
     *
134
     * @throws NonUniqueResultException
135
     */
136 2
    private function isUnique(string $column, string $value, ?string $id = null): bool
137
    {
138
        // Build query
139 2
        $query = $this
140 2
            ->createQueryBuilder('u')
141 2
            ->select('u')
142 2
            ->where('u.' . $column . ' = :value')
143 2
            ->setParameter('value', $value);
144
145 2
        if ($id !== null) {
146
            $query
147 2
                ->andWhere('u.id <> :id')
148 2
                ->setParameter('id', $id, UuidHelper::getType($id));
149
        }
150
151 2
        return $query->getQuery()->getOneOrNullResult() === null;
152
    }
153
}
154