feat : mise à jour de la structure du projet
This commit is contained in:
12
src/Module/Commercial/CommercialModule.php
Normal file
12
src/Module/Commercial/CommercialModule.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Commercial;
|
||||
|
||||
final class CommercialModule
|
||||
{
|
||||
public const string ID = 'commercial';
|
||||
public const string LABEL = 'Commercial';
|
||||
public const bool REQUIRED = false;
|
||||
}
|
||||
29
src/Module/Core/Application/DTO/UserOutput.php
Normal file
29
src/Module/Core/Application/DTO/UserOutput.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Application\DTO;
|
||||
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class UserOutput
|
||||
{
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public string $username,
|
||||
/** @var list<string> */
|
||||
public array $roles,
|
||||
public ?DateTimeImmutable $createdAt,
|
||||
) {}
|
||||
|
||||
public static function fromEntity(User $user): self
|
||||
{
|
||||
return new self(
|
||||
id: $user->getId(),
|
||||
username: $user->getUsername(),
|
||||
roles: $user->getRoles(),
|
||||
createdAt: $user->getCreatedAt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
12
src/Module/Core/CoreModule.php
Normal file
12
src/Module/Core/CoreModule.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core;
|
||||
|
||||
final class CoreModule
|
||||
{
|
||||
public const string ID = 'core';
|
||||
public const string LABEL = 'Core';
|
||||
public const bool REQUIRED = true;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
namespace App\Module\Core\Domain\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
@@ -10,9 +10,9 @@ use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use App\Api\Auth\State\MeProvider;
|
||||
use App\Api\Auth\State\UserPasswordHasherProcessor;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Module\Core\Infrastructure\ApiPlatform\State\Processor\UserPasswordHasherProcessor;
|
||||
use App\Module\Core\Infrastructure\ApiPlatform\State\Provider\MeProvider;
|
||||
use App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
@@ -38,7 +38,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
|
||||
{
|
||||
22
src/Module/Core/Domain/Event/UserCreated.php
Normal file
22
src/Module/Core/Domain/Event/UserCreated.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Domain\Event;
|
||||
|
||||
use App\Shared\Domain\Event\DomainEventInterface;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class UserCreated implements DomainEventInterface
|
||||
{
|
||||
public function __construct(
|
||||
public int $userId,
|
||||
public string $username,
|
||||
private DateTimeImmutable $occurredAt = new DateTimeImmutable(),
|
||||
) {}
|
||||
|
||||
public function occurredAt(): DateTimeImmutable
|
||||
{
|
||||
return $this->occurredAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Domain\Repository;
|
||||
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
|
||||
interface UserRepositoryInterface
|
||||
{
|
||||
public function findById(int $id): ?User;
|
||||
|
||||
public function findByUsername(string $username): ?User;
|
||||
|
||||
public function save(User $user): void;
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Api\Auth\State;
|
||||
namespace App\Module\Core\Infrastructure\ApiPlatform\State\Processor;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use App\Entity\User;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
@@ -2,19 +2,18 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Api\Auth\State;
|
||||
namespace App\Module\Core\Infrastructure\ApiPlatform\State\Provider;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
/**
|
||||
* @implements ProviderInterface<\App\Entity\User>
|
||||
* @implements ProviderInterface<object>
|
||||
*/
|
||||
class MeProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Security $security,
|
||||
private readonly \Symfony\Bundle\SecurityBundle\Security $security,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
namespace App\Module\Core\Infrastructure\Console;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\DataFixtures;
|
||||
namespace App\Module\Core\Infrastructure\DataFixtures;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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 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);
|
||||
}
|
||||
|
||||
public function findById(int $id): ?User
|
||||
{
|
||||
return $this->find($id);
|
||||
}
|
||||
|
||||
public function findByUsername(string $username): ?User
|
||||
{
|
||||
return $this->findOneBy(['username' => $username]);
|
||||
}
|
||||
|
||||
public function save(User $user): void
|
||||
{
|
||||
$this->getEntityManager()->persist($user);
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\User;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<User>
|
||||
*/
|
||||
class UserRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, User::class);
|
||||
}
|
||||
}
|
||||
10
src/Shared/Application/Bus/CommandBusInterface.php
Normal file
10
src/Shared/Application/Bus/CommandBusInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Application\Bus;
|
||||
|
||||
interface CommandBusInterface
|
||||
{
|
||||
public function dispatch(object $command): void;
|
||||
}
|
||||
10
src/Shared/Application/Bus/QueryBusInterface.php
Normal file
10
src/Shared/Application/Bus/QueryBusInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Application\Bus;
|
||||
|
||||
interface QueryBusInterface
|
||||
{
|
||||
public function ask(object $query): mixed;
|
||||
}
|
||||
10
src/Shared/Domain/Contract/TenantAwareInterface.php
Normal file
10
src/Shared/Domain/Contract/TenantAwareInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Domain\Contract;
|
||||
|
||||
interface TenantAwareInterface
|
||||
{
|
||||
public function getTenantId(): ?string;
|
||||
}
|
||||
10
src/Shared/Domain/Contract/UserResolverInterface.php
Normal file
10
src/Shared/Domain/Contract/UserResolverInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Domain\Contract;
|
||||
|
||||
interface UserResolverInterface
|
||||
{
|
||||
public function resolve(int $id): ?object;
|
||||
}
|
||||
12
src/Shared/Domain/Event/DomainEventInterface.php
Normal file
12
src/Shared/Domain/Event/DomainEventInterface.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Domain\Event;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface DomainEventInterface
|
||||
{
|
||||
public function occurredAt(): DateTimeImmutable;
|
||||
}
|
||||
31
src/Shared/Domain/ValueObject/Email.php
Normal file
31
src/Shared/Domain/ValueObject/Email.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Domain\ValueObject;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final readonly class Email
|
||||
{
|
||||
public readonly string $value;
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new InvalidArgumentException(sprintf('"%s" is not a valid email address.', $value));
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function equals(self $other): bool
|
||||
{
|
||||
return $this->value === $other->value;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Api\Shared\Resource;
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\Resource;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Api\Shared\State\AppVersionProvider;
|
||||
use App\Shared\Infrastructure\ApiPlatform\State\AppVersionProvider;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\Resource;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Shared\Infrastructure\ApiPlatform\State\ModulesProvider;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
uriTemplate: '/modules',
|
||||
provider: ModulesProvider::class,
|
||||
),
|
||||
],
|
||||
)]
|
||||
class ModulesResource
|
||||
{
|
||||
/** @var list<string> */
|
||||
public array $modules = [];
|
||||
|
||||
/** @param list<string> $modules */
|
||||
public function __construct(array $modules = [])
|
||||
{
|
||||
$this->modules = $modules;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\Resource;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Shared\Infrastructure\ApiPlatform\State\SidebarProvider;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
uriTemplate: '/sidebar',
|
||||
provider: SidebarProvider::class,
|
||||
),
|
||||
],
|
||||
)]
|
||||
class SidebarResource
|
||||
{
|
||||
/** @var list<array{label: string, icon: string, items: list<array{label: string, to: string, icon: string}>}> */
|
||||
public array $sections = [];
|
||||
|
||||
/** @var list<string> */
|
||||
public array $disabledRoutes = [];
|
||||
|
||||
/**
|
||||
* @param list<array{label: string, icon: string, items: list<array{label: string, to: string, icon: string}>}> $sections
|
||||
* @param list<string> $disabledRoutes
|
||||
*/
|
||||
public function __construct(array $sections = [], array $disabledRoutes = [])
|
||||
{
|
||||
$this->sections = $sections;
|
||||
$this->disabledRoutes = $disabledRoutes;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Api\Shared\State;
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Api\Shared\Resource\AppVersion;
|
||||
use App\Shared\Infrastructure\ApiPlatform\Resource\AppVersion;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Shared\Infrastructure\ApiPlatform\Resource\ModulesResource;
|
||||
|
||||
/**
|
||||
* @implements ProviderInterface<object>
|
||||
*/
|
||||
class ModulesProvider implements ProviderInterface
|
||||
{
|
||||
/** @var list<string> */
|
||||
private readonly array $activeModuleIds;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$configPath = dirname(__DIR__, 5).'/config/modules.php';
|
||||
$moduleClasses = file_exists($configPath) ? require $configPath : [];
|
||||
|
||||
$ids = [];
|
||||
foreach ($moduleClasses as $moduleClass) {
|
||||
if (defined($moduleClass.'::ID')) {
|
||||
$ids[] = $moduleClass::ID;
|
||||
}
|
||||
}
|
||||
|
||||
$this->activeModuleIds = $ids;
|
||||
}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||
{
|
||||
return new ModulesResource($this->activeModuleIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Shared\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Shared\Infrastructure\ApiPlatform\Resource\SidebarResource;
|
||||
|
||||
/**
|
||||
* @implements ProviderInterface<object>
|
||||
*/
|
||||
class SidebarProvider implements ProviderInterface
|
||||
{
|
||||
/** @var list<string> */
|
||||
private readonly array $activeModuleIds;
|
||||
|
||||
/** @var list<array{label: string, icon: string, items: list<array{label: string, to: string, icon: string, module: string}>}> */
|
||||
private readonly array $sidebarConfig;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$configDir = dirname(__DIR__, 5).'/config';
|
||||
|
||||
// Load active modules
|
||||
$modulesFile = $configDir.'/modules.php';
|
||||
$moduleClasses = file_exists($modulesFile) ? require $modulesFile : [];
|
||||
|
||||
$ids = [];
|
||||
foreach ($moduleClasses as $moduleClass) {
|
||||
if (defined($moduleClass.'::ID')) {
|
||||
$ids[] = $moduleClass::ID;
|
||||
}
|
||||
}
|
||||
$this->activeModuleIds = $ids;
|
||||
|
||||
// Load sidebar config
|
||||
$sidebarFile = $configDir.'/sidebar.php';
|
||||
$this->sidebarConfig = file_exists($sidebarFile) ? require $sidebarFile : [];
|
||||
}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object
|
||||
{
|
||||
$sections = [];
|
||||
$disabledRoutes = [];
|
||||
|
||||
foreach ($this->sidebarConfig as $section) {
|
||||
$items = [];
|
||||
foreach ($section['items'] ?? [] as $item) {
|
||||
$isActive = in_array($item['module'] ?? null, $this->activeModuleIds, true);
|
||||
|
||||
if (!$isActive) {
|
||||
if (isset($item['to'])) {
|
||||
$disabledRoutes[] = $item['to'];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'label' => $item['label'],
|
||||
'to' => $item['to'],
|
||||
'icon' => $item['icon'],
|
||||
];
|
||||
}
|
||||
|
||||
if ([] === $items) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sections[] = [
|
||||
'label' => $section['label'],
|
||||
'icon' => $section['icon'],
|
||||
'items' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
return new SidebarResource($sections, array_values(array_unique($disabledRoutes)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user