refactor(core) : move user repository/providers to core and migrate all consumers off App\Entity\User

This commit is contained in:
Matthieu
2026-06-19 16:16:44 +02:00
parent d70925b812
commit 0b4874e94d
53 changed files with 109 additions and 115 deletions
+4 -4
View File
@@ -12,10 +12,10 @@ use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Enum\ContractType;
use App\Repository\UserRepository;
use App\Module\Core\Infrastructure\ApiPlatform\State\MeProvider;
use App\Module\Core\Infrastructure\ApiPlatform\State\UserPasswordHasherProcessor;
use App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository;
use App\Shared\Domain\Contract\UserInterface as SharedUserInterface;
use App\State\MeProvider;
use App\State\UserPasswordHasherProcessor;
use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
@@ -43,7 +43,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
],
denormalizationContext: ['groups' => ['user:write']],
)]
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Entity(repositoryClass: DoctrineUserRepository::class)]
#[ORM\Table(name: '`user`')]
class User implements UserInterface, PasswordAuthenticatedUserInterface, SharedUserInterface
{
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Module\Core\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Module\Core\Domain\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;
/**
* @implements ProviderInterface<User>
*/
final readonly class MeProvider implements ProviderInterface
{
public function __construct(
private Security $security,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): User
{
// @var User $user
return $this->security->getUser();
}
}
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Module\Core\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Module\Core\Domain\Entity\User;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
/**
* @implements ProcessorInterface<User, User>
*/
final readonly class UserPasswordHasherProcessor implements ProcessorInterface
{
/**
* @param ProcessorInterface<User, User> $persistProcessor
*/
public function __construct(
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
private ProcessorInterface $persistProcessor,
private UserPasswordHasherInterface $passwordHasher,
) {}
/**
* @param User $data
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
{
$plainPassword = $data->getPlainPassword();
if (null !== $plainPassword && '' !== $plainPassword) {
$data->setPassword($this->passwordHasher->hashPassword($data, $plainPassword));
$data->setPlainPassword(null);
}
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
}
}
@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace App\Module\Core\Infrastructure\Doctrine;
use App\Module\Core\Domain\Entity\User;
use App\Module\Core\Domain\Repository\UserRepositoryInterface;
use App\Shared\Domain\Contract\UserInterface;
use DateTimeInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<User>
*/
class DoctrineUserRepository extends ServiceEntityRepository implements UserRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
/**
* @return list<UserInterface>
*/
public function findByRole(string $role): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = 'SELECT id FROM "user" WHERE roles::text LIKE :role';
$ids = $conn->executeQuery($sql, ['role' => '%"'.$role.'"%'])->fetchFirstColumn();
if ([] === $ids) {
return [];
}
return $this->createQueryBuilder('u')
->where('u.id IN (:ids)')
->setParameter('ids', $ids)
->getQuery()
->getResult()
;
}
/**
* Employees active on the given date (hired on/before it, not yet left).
*
* @return list<UserInterface>
*/
public function findActiveEmployees(DateTimeInterface $date): array
{
$dateStr = $date->format('Y-m-d');
return $this->createQueryBuilder('u')
->where('u.isEmployee = true')
->andWhere('u.hireDate IS NULL OR u.hireDate <= :date')
->andWhere('u.endDate IS NULL OR u.endDate >= :date')
->setParameter('date', $dateStr)
->orderBy('u.username', 'ASC')
->getQuery()
->getResult()
;
}
public function findOneByUsername(string $username): ?UserInterface
{
return $this->findOneBy(['username' => $username]);
}
}
-8
View File
@@ -1,8 +0,0 @@
<?php
declare(strict_types=1);
use App\Entity\User;
if (!class_exists(User::class, false)) {
class_alias(App\Module\Core\Domain\Entity\User::class, User::class);
}