-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ajout du handler pour créer un token (#1159)
- Loading branch information
Showing
8 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Application\User\Command; | ||
|
||
use App\Application\CommandInterface; | ||
|
||
final readonly class CreateTokenCommand implements CommandInterface | ||
{ | ||
public function __construct( | ||
public string $email, | ||
public string $type, | ||
) { | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/Application/User/Command/CreateTokenCommandHandler.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Application\User\Command; | ||
|
||
use App\Application\DateUtilsInterface; | ||
use App\Application\IdFactoryInterface; | ||
use App\Domain\User\Exception\UserNotFoundException; | ||
use App\Domain\User\Repository\TokenRepositoryInterface; | ||
use App\Domain\User\Repository\UserRepositoryInterface; | ||
use App\Domain\User\Token; | ||
use App\Domain\User\TokenGenerator; | ||
use App\Domain\User\User; | ||
|
||
final readonly class CreateTokenCommandHandler | ||
{ | ||
public function __construct( | ||
private IdFactoryInterface $idFactory, | ||
private UserRepositoryInterface $userRepository, | ||
private TokenRepositoryInterface $tokenRepository, | ||
private DateUtilsInterface $dateUtils, | ||
private TokenGenerator $tokenGenerator, | ||
) { | ||
} | ||
|
||
public function __invoke(CreateTokenCommand $command): string | ||
{ | ||
$user = $this->userRepository->findOneByEmail($command->email); | ||
if (!$user instanceof User) { | ||
throw new UserNotFoundException(); | ||
} | ||
|
||
$expirationDate = $this->dateUtils->getNow()->modify('+1 day'); | ||
$token = $this->tokenGenerator->generate(); | ||
|
||
$this->tokenRepository->add( | ||
new Token( | ||
uuid: $this->idFactory->make(), | ||
token: $token, | ||
type: $command->type, | ||
user: $user, | ||
expirationDate: $expirationDate, | ||
), | ||
); | ||
|
||
return $token; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Domain\User\Exception; | ||
|
||
final class UserNotFoundException extends \Exception | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Domain\User\Repository; | ||
|
||
use App\Domain\User\Token; | ||
|
||
interface TokenRepositoryInterface | ||
{ | ||
public function add(Token $token): Token; | ||
|
||
public function remove(Token $token): void; | ||
|
||
public function findOneByTokenAndType(string $token, string $type): ?Token; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Domain\User; | ||
|
||
final class TokenGenerator | ||
{ | ||
public function generate(): string | ||
{ | ||
return rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '='); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/Infrastructure/Persistence/Doctrine/Repository/User/TokenRepository.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Infrastructure\Persistence\Doctrine\Repository\User; | ||
|
||
use App\Domain\User\Repository\TokenRepositoryInterface; | ||
use App\Domain\User\Token; | ||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | ||
use Doctrine\Persistence\ManagerRegistry; | ||
|
||
final class TokenRepository extends ServiceEntityRepository implements TokenRepositoryInterface | ||
{ | ||
public function __construct(ManagerRegistry $registry) | ||
{ | ||
parent::__construct($registry, Token::class); | ||
} | ||
|
||
public function add(Token $token): Token | ||
{ | ||
$this->getEntityManager()->persist($token); | ||
|
||
return $token; | ||
} | ||
|
||
public function remove(Token $token): void | ||
{ | ||
$this->getEntityManager()->remove($token); | ||
} | ||
|
||
public function findOneByTokenAndType(string $token, string $type): ?Token | ||
{ | ||
return $this->createQueryBuilder('t') | ||
->where('t.token = :token') | ||
->andWhere('t.type = :type') | ||
->setParameters([ | ||
'token' => $token, | ||
'type' => $type, | ||
]) | ||
->setMaxResults(1) | ||
->getQuery() | ||
->getOneOrNullResult() | ||
; | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
tests/Unit/Application/User/Command/CreateTokenCommandHandlerTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Tests\Unit\Application\User\Command; | ||
|
||
use App\Application\DateUtilsInterface; | ||
use App\Application\IdFactoryInterface; | ||
use App\Application\User\Command\CreateTokenCommand; | ||
use App\Application\User\Command\CreateTokenCommandHandler; | ||
use App\Domain\User\Enum\TokenTypeEnum; | ||
use App\Domain\User\Exception\UserNotFoundException; | ||
use App\Domain\User\Repository\TokenRepositoryInterface; | ||
use App\Domain\User\Repository\UserRepositoryInterface; | ||
use App\Domain\User\Token; | ||
use App\Domain\User\TokenGenerator; | ||
use App\Domain\User\User; | ||
use PHPUnit\Framework\MockObject\MockObject; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
final class CreateTokenCommandHandlerTest extends TestCase | ||
{ | ||
private MockObject $idFactory; | ||
private MockObject $userRepository; | ||
private MockObject $tokenRepository; | ||
private MockObject $dateUtils; | ||
private MockObject $tokenGenerator; | ||
|
||
public function setUp(): void | ||
{ | ||
$this->idFactory = $this->createMock(IdFactoryInterface::class); | ||
$this->userRepository = $this->createMock(UserRepositoryInterface::class); | ||
$this->tokenRepository = $this->createMock(TokenRepositoryInterface::class); | ||
$this->dateUtils = $this->createMock(DateUtilsInterface::class); | ||
$this->tokenGenerator = $this->createMock(TokenGenerator::class); | ||
} | ||
|
||
public function testCreateToken(): void | ||
{ | ||
$this->tokenGenerator | ||
->expects(self::once()) | ||
->method('generate') | ||
->willReturn('myToken'); | ||
|
||
$expirationDate = new \DateTimeImmutable('2023-08-31 08:00:00'); | ||
$this->dateUtils | ||
->expects(self::once()) | ||
->method('getNow') | ||
->willReturn($expirationDate); | ||
|
||
$user = $this->createMock(User::class); | ||
$this->userRepository | ||
->expects(self::once()) | ||
->method('findOneByEmail') | ||
->with('[email protected]') | ||
->willReturn($user); | ||
|
||
$this->idFactory | ||
->expects(self::once()) | ||
->method('make') | ||
->willReturn('ed81607d-476c-4e52-a234-90fddf3ba550'); | ||
|
||
$this->tokenRepository | ||
->expects(self::once()) | ||
->method('add') | ||
->with( | ||
new Token( | ||
uuid: 'ed81607d-476c-4e52-a234-90fddf3ba550', | ||
token: 'myToken', | ||
type: TokenTypeEnum::FORGOT_PASSWORD->value, | ||
user: $user, | ||
expirationDate: new \DateTime('2023-09-01 08:00:00'), | ||
), | ||
); | ||
|
||
$handler = new CreateTokenCommandHandler( | ||
$this->idFactory, | ||
$this->userRepository, | ||
$this->tokenRepository, | ||
$this->dateUtils, | ||
$this->tokenGenerator, | ||
); | ||
$this->assertSame( | ||
'myToken', | ||
($handler)(new CreateTokenCommand('[email protected]', TokenTypeEnum::FORGOT_PASSWORD->value)), | ||
); | ||
} | ||
|
||
public function testUserNotFound(): void | ||
{ | ||
$this->expectException(UserNotFoundException::class); | ||
|
||
$this->tokenGenerator | ||
->expects(self::never()) | ||
->method('generate'); | ||
|
||
$this->dateUtils | ||
->expects(self::never()) | ||
->method('getNow'); | ||
|
||
$this->userRepository | ||
->expects(self::once()) | ||
->method('findOneByEmail') | ||
->with('[email protected]') | ||
->willReturn(null); | ||
|
||
$this->idFactory | ||
->expects(self::never()) | ||
->method('make'); | ||
|
||
$this->tokenRepository | ||
->expects(self::never()) | ||
->method('add'); | ||
|
||
$handler = new CreateTokenCommandHandler( | ||
$this->idFactory, | ||
$this->userRepository, | ||
$this->tokenRepository, | ||
$this->dateUtils, | ||
$this->tokenGenerator, | ||
); | ||
|
||
($handler)(new CreateTokenCommand('[email protected]', TokenTypeEnum::FORGOT_PASSWORD->value)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Tests\Unit\Domain\User; | ||
|
||
use App\Domain\User\TokenGenerator; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
final class TokenGeneratorTest extends TestCase | ||
{ | ||
public function testGenerate(): void | ||
{ | ||
$tokenGenerator = new TokenGenerator(); | ||
|
||
$this->assertNotEmpty($tokenGenerator->generate()); | ||
$this->assertSame(43, \strlen($tokenGenerator->generate())); | ||
} | ||
} |