Passed
Push — master ( c0736e...0c280c )
by Daniel
06:26
created

DoctrineRefreshTokenStorage::expireToken()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 8
ccs 0
cts 6
cp 0
crap 12
rs 10
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[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
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\RefreshToken\Storage;
15
16
use Doctrine\ORM\EntityManager;
17
use Doctrine\ORM\EntityNotFoundException;
18
use Doctrine\Persistence\ManagerRegistry;
19
use Silverback\ApiComponentsBundle\RefreshToken\RefreshToken;
20
use Silverback\ApiComponentsBundle\Repository\Core\RefreshTokenRepository;
21
use Symfony\Component\Security\Core\User\UserInterface;
22
23
/**
24
 * @author Vincent Chalamon <[email protected]>
25
 */
26
final class DoctrineRefreshTokenStorage implements RefreshTokenStorageInterface
27
{
28
    private ManagerRegistry $registry;
29
    private int $ttl;
30
    private string $className;
31
32 7
    public function __construct(ManagerRegistry $registry, int $ttl, array $options)
33
    {
34 7
        $this->registry = $registry;
35 7
        $this->ttl = $ttl;
36
37 7
        if (!isset($options['class'])) {
38
            throw new \InvalidArgumentException('You must specify silverback_api_components.refresh.token.options.class option.');
39
        }
40
41 7
        $this->className = $options['class'];
42 7
    }
43
44
    public function findOneByUser(UserInterface $user): ?RefreshToken
45
    {
46
        $em = $this->getEntityManager();
47
        $repository = $em->getRepository($this->className);
48
        if (!$repository instanceof RefreshTokenRepository) {
49
            throw new \InvalidArgumentException('RefreshToken entity repository must be instance of ' . RefreshTokenRepository::class);
50
        }
51
52
        return $repository->findOneByUser($user);
53
    }
54
55
    public function create(UserInterface $user, bool $flush = true): RefreshToken
56
    {
57
        $className = $this->className;
58
        /** @var RefreshToken $refreshToken */
59
        $refreshToken = new $className();
60
        $refreshToken->setCreatedAt(new \DateTimeImmutable());
61
        $refreshToken->setExpiresAt(new \DateTimeImmutable("$this->ttl seconds"));
62
        $refreshToken->setUser($user);
63
64
        $em = $this->getEntityManager();
65
        $em->persist($refreshToken);
66
67
        if ($flush) {
68
            $em->flush($refreshToken);
69
        }
70
71
        return $refreshToken;
72
    }
73
74
    // in 1 transaction so concurrent requests will not find no valid request token
75
    public function createAndExpire(UserInterface $user, RefreshToken $refreshToken): RefreshToken
76
    {
77
        $em = $this->getEntityManager();
78
        $newToken = $this->create($user, false);
79
        $this->expireToken($refreshToken, false);
80
        $em->flush();
81
82
        return $newToken;
83
    }
84
85
    public function createAndExpireAll(UserInterface $user): RefreshToken
86
    {
87
        $em = $this->getEntityManager();
88
        $newToken = $this->create($user, false);
89
        $this->expireAll($user, false);
90
        $em->flush();
91
92
        return $newToken;
93
    }
94
95
    public function expireAll(?UserInterface $user, bool $flush = true): void
96
    {
97
        $em = $this->getEntityManager();
98
        $repository = $em->getRepository($this->className);
99
        $refreshTokens = $user ? $repository->findBy(['user' => $user]) : $repository->findAll();
100
101
        foreach ($refreshTokens as $refreshToken) {
102
            /* @var RefreshToken $refreshToken */
103
            $this->expireToken($refreshToken, false);
104
        }
105
        if ($flush) {
106
            $em->flush();
107
        }
108
    }
109
110
    public function expireToken(RefreshToken $refreshToken, bool $flush = true): void
111
    {
112
        $em = $this->getEntityManager();
113
        if (!$refreshToken->isExpired()) {
114
            $refreshToken->setExpiresAt(new \DateTimeImmutable());
115
        }
116
        if ($flush) {
117
            $em->flush();
118
        }
119
    }
120
121
    private function getEntityManager(): EntityManager
122
    {
123
        /** @var EntityManager|null $em */
124
        $em = $this->registry->getManagerForClass($this->className);
125
        if (!$em) {
0 ignored issues
show
introduced by
$em is of type Doctrine\ORM\EntityManager, thus it always evaluated to true.
Loading history...
126
            throw new EntityNotFoundException('No entity found for class RefreshToken::class.');
127
        }
128
129
        return $em;
130
    }
131
}
132