UserRepository::isUnique()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

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