feat(directory) : migrate Client into Directory module (back)
LST-58 (2.4), part 1/2 — Client move. Prospect + repertoire front are pending the product spec and will be added on this branch afterward. - Client entity moved to src/Module/Directory/Domain/Entity; repository split into Domain/Repository/ClientRepositoryInterface + Doctrine impl (bound in services.yaml). 5 client MCP tools moved to Infrastructure/Mcp/Tool, now injecting the interface. - resolve_target_entities ClientInterface repointed to Directory\Client; Directory mapping added; DirectoryModule registered (id directory, 2 RBAC perms). Client.projects relation now uses ProjectInterface -> Directory no longer depends on ProjectManagement. - ProjectManagement Create/UpdateProjectTool inject Directory's ClientRepositoryInterface; Serializer and fixtures repointed. - Garde-fous: #[Auditable] + Timestampable/Blamable on Client (additive migration: created_at/updated_at + created_by/updated_by FK ON DELETE SET NULL + COMMENT). 161 tests green, mapping valid, no API route regression, cs-fixer clean.
This commit is contained in:
@@ -9,6 +9,7 @@ declare(strict_types=1);
|
||||
|
||||
use App\Module\Absence\AbsenceModule;
|
||||
use App\Module\Core\CoreModule;
|
||||
use App\Module\Directory\DirectoryModule;
|
||||
use App\Module\ProjectManagement\ProjectManagementModule;
|
||||
use App\Module\TimeTracking\TimeTrackingModule;
|
||||
|
||||
@@ -17,4 +18,5 @@ return [
|
||||
TimeTrackingModule::class,
|
||||
ProjectManagementModule::class,
|
||||
AbsenceModule::class,
|
||||
DirectoryModule::class,
|
||||
];
|
||||
|
||||
@@ -25,7 +25,7 @@ doctrine:
|
||||
App\Shared\Domain\Contract\ProjectInterface: App\Module\ProjectManagement\Domain\Entity\Project
|
||||
App\Shared\Domain\Contract\TaskInterface: App\Module\ProjectManagement\Domain\Entity\Task
|
||||
App\Shared\Domain\Contract\TaskTagInterface: App\Module\ProjectManagement\Domain\Entity\TaskTag
|
||||
App\Shared\Domain\Contract\ClientInterface: App\Entity\Client
|
||||
App\Shared\Domain\Contract\ClientInterface: App\Module\Directory\Domain\Entity\Client
|
||||
mappings:
|
||||
App:
|
||||
type: attribute
|
||||
@@ -53,6 +53,11 @@ doctrine:
|
||||
is_bundle: false
|
||||
dir: '%kernel.project_dir%/src/Module/Absence/Domain/Entity'
|
||||
prefix: 'App\Module\Absence\Domain\Entity'
|
||||
Directory:
|
||||
type: attribute
|
||||
is_bundle: false
|
||||
dir: '%kernel.project_dir%/src/Module/Directory/Domain/Entity'
|
||||
prefix: 'App\Module\Directory\Domain\Entity'
|
||||
controller_resolver:
|
||||
auto_mapping: false
|
||||
|
||||
|
||||
@@ -99,4 +99,6 @@ services:
|
||||
|
||||
App\Module\Absence\Domain\Repository\AbsenceBalanceRepositoryInterface: '@App\Module\Absence\Infrastructure\Doctrine\DoctrineAbsenceBalanceRepository'
|
||||
|
||||
App\Module\Directory\Domain\Repository\ClientRepositoryInterface: '@App\Module\Directory\Infrastructure\Doctrine\DoctrineClientRepository'
|
||||
|
||||
App\Shared\Domain\Contract\NotifierInterface: '@App\Module\Core\Infrastructure\Notifier'
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Directory module: add Timestampable/Blamable columns to client.
|
||||
*
|
||||
* Client (moved to App\Module\Directory\Domain\Entity) adopts
|
||||
* TimestampableBlamableTrait. This migration is purely additive — nullable
|
||||
* columns + nullable FK to "user" with ON DELETE SET NULL. No DROP/ALTER on
|
||||
* existing data. Columns are lowercase snake_case. Hand-written to guarantee
|
||||
* zero destructive instruction.
|
||||
*/
|
||||
final class Version20260620180000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Directory: add timestampable/blamable columns to client (additive)';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE client ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE client ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE client ADD created_by INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE client ADD updated_by INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455DE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
|
||||
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C744045516FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
|
||||
$this->addSql('CREATE INDEX IDX_C7440455DE12AB56 ON client (created_by)');
|
||||
$this->addSql('CREATE INDEX IDX_C744045516FE72E1 ON client (updated_by)');
|
||||
$this->addSql("COMMENT ON COLUMN client.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'");
|
||||
$this->addSql("COMMENT ON COLUMN client.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'");
|
||||
$this->addSql("COMMENT ON COLUMN client.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'");
|
||||
$this->addSql("COMMENT ON COLUMN client.updated_by IS 'User who last updated the entry (Blamable, FK user.id, SET NULL on delete)'");
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE client DROP CONSTRAINT FK_C7440455DE12AB56');
|
||||
$this->addSql('ALTER TABLE client DROP CONSTRAINT FK_C744045516FE72E1');
|
||||
$this->addSql('DROP INDEX IDX_C7440455DE12AB56');
|
||||
$this->addSql('DROP INDEX IDX_C744045516FE72E1');
|
||||
$this->addSql('ALTER TABLE client DROP created_at');
|
||||
$this->addSql('ALTER TABLE client DROP updated_at');
|
||||
$this->addSql('ALTER TABLE client DROP created_by');
|
||||
$this->addSql('ALTER TABLE client DROP updated_by');
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\DataFixtures;
|
||||
|
||||
use App\Entity\Client;
|
||||
use App\Entity\MailConfiguration;
|
||||
use App\Entity\ZimbraConfiguration;
|
||||
use App\Enum\ContractType;
|
||||
@@ -15,6 +14,7 @@ use App\Module\Absence\Domain\Enum\AbsenceStatus;
|
||||
use App\Module\Absence\Domain\Enum\AbsenceType;
|
||||
use App\Module\Core\Application\Rbac\RbacSeeder;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Project;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Task;
|
||||
use App\Module\ProjectManagement\Domain\Entity\TaskEffort;
|
||||
|
||||
@@ -4,11 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool;
|
||||
|
||||
use App\Entity\Client;
|
||||
use App\Module\Absence\Domain\Entity\AbsenceBalance;
|
||||
use App\Module\Absence\Domain\Entity\AbsencePolicy;
|
||||
use App\Module\Absence\Domain\Entity\AbsenceRequest;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Project;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Task;
|
||||
use App\Module\ProjectManagement\Domain\Entity\TaskDocument;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Directory;
|
||||
|
||||
use App\Shared\Domain\Module\ModuleInterface;
|
||||
|
||||
final class DirectoryModule implements ModuleInterface
|
||||
{
|
||||
public static function id(): string
|
||||
{
|
||||
return 'directory';
|
||||
}
|
||||
|
||||
public static function label(): string
|
||||
{
|
||||
return 'Répertoire';
|
||||
}
|
||||
|
||||
public static function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permissions RBAC fin du Module Directory.
|
||||
*
|
||||
* Additif : alimente le catalogue RBAC. La sécurité des opérations API
|
||||
* reste en ROLE_USER/ROLE_ADMIN (non recâblée ici).
|
||||
*
|
||||
* @return list<array{code: string, label: string}>
|
||||
*/
|
||||
public static function permissions(): array
|
||||
{
|
||||
return [
|
||||
['code' => 'directory.clients.view', 'label' => 'Voir les clients'],
|
||||
['code' => 'directory.clients.manage', 'label' => 'Gérer les clients'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
namespace App\Module\Directory\Domain\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
@@ -10,14 +10,19 @@ use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Project;
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Module\Directory\Infrastructure\Doctrine\DoctrineClientRepository;
|
||||
use App\Shared\Domain\Attribute\Auditable;
|
||||
use App\Shared\Domain\Contract\BlamableInterface;
|
||||
use App\Shared\Domain\Contract\ClientInterface;
|
||||
use App\Shared\Domain\Contract\ProjectInterface;
|
||||
use App\Shared\Domain\Contract\TimestampableInterface;
|
||||
use App\Shared\Domain\Trait\TimestampableBlamableTrait;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[Auditable]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"),
|
||||
@@ -30,9 +35,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
|
||||
denormalizationContext: ['groups' => ['client:write']],
|
||||
order: ['name' => 'ASC'],
|
||||
)]
|
||||
#[ORM\Entity(repositoryClass: ClientRepository::class)]
|
||||
class Client implements ClientInterface
|
||||
#[ORM\Entity(repositoryClass: DoctrineClientRepository::class)]
|
||||
class Client implements ClientInterface, TimestampableInterface, BlamableInterface
|
||||
{
|
||||
use TimestampableBlamableTrait;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
@@ -63,8 +70,8 @@ class Client implements ClientInterface
|
||||
#[Groups(['client:read', 'client:write'])]
|
||||
private ?string $postalCode = null;
|
||||
|
||||
/** @var Collection<int, Project> */
|
||||
#[ORM\OneToMany(targetEntity: Project::class, mappedBy: 'client')]
|
||||
/** @var Collection<int, ProjectInterface> */
|
||||
#[ORM\OneToMany(targetEntity: ProjectInterface::class, mappedBy: 'client')]
|
||||
private Collection $projects;
|
||||
|
||||
public function __construct()
|
||||
@@ -149,7 +156,7 @@ class Client implements ClientInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return Collection<int, Project> */
|
||||
/** @return Collection<int, ProjectInterface> */
|
||||
public function getProjects(): Collection
|
||||
{
|
||||
return $this->projects;
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Directory\Domain\Repository;
|
||||
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
|
||||
interface ClientRepositoryInterface
|
||||
{
|
||||
public function findById(int $id): ?Client;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $criteria
|
||||
* @param null|array<string, string> $orderBy
|
||||
*
|
||||
* @return Client[]
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Directory\Infrastructure\Doctrine;
|
||||
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Client>
|
||||
*/
|
||||
final class DoctrineClientRepository extends ServiceEntityRepository implements ClientRepositoryInterface
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Client::class);
|
||||
}
|
||||
|
||||
public function findById(int $id): ?Client
|
||||
{
|
||||
return $this->find($id);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2,10 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\Reference;
|
||||
namespace App\Module\Directory\Infrastructure\Mcp\Tool;
|
||||
|
||||
use App\Entity\Client;
|
||||
use App\Mcp\Tool\Serializer;
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
+4
-4
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\Reference;
|
||||
namespace App\Module\Directory\Infrastructure\Mcp\Tool;
|
||||
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
@@ -17,7 +17,7 @@ use function sprintf;
|
||||
class DeleteClientTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
@@ -28,7 +28,7 @@ class DeleteClientTool
|
||||
throw new AccessDeniedException('Access denied: ROLE_ADMIN required.');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->find($id);
|
||||
$client = $this->clientRepository->findById($id);
|
||||
if (null === $client) {
|
||||
throw new InvalidArgumentException(sprintf('Client with ID %d not found.', $id));
|
||||
}
|
||||
+4
-4
@@ -2,10 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\Reference;
|
||||
namespace App\Module\Directory\Infrastructure\Mcp\Tool;
|
||||
|
||||
use App\Mcp\Tool\Serializer;
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use InvalidArgumentException;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
@@ -17,7 +17,7 @@ use function sprintf;
|
||||
class GetClientTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
@@ -27,7 +27,7 @@ class GetClientTool
|
||||
throw new AccessDeniedException('Access denied: ROLE_ADMIN required.');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->find($id);
|
||||
$client = $this->clientRepository->findById($id);
|
||||
if (null === $client) {
|
||||
throw new InvalidArgumentException(sprintf('Client with ID %d not found.', $id));
|
||||
}
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\Reference;
|
||||
namespace App\Module\Directory\Infrastructure\Mcp\Tool;
|
||||
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
@@ -13,7 +13,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
class ListClientsTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
+4
-4
@@ -2,10 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\Reference;
|
||||
namespace App\Module\Directory\Infrastructure\Mcp\Tool;
|
||||
|
||||
use App\Mcp\Tool\Serializer;
|
||||
use App\Repository\ClientRepository;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
@@ -18,7 +18,7 @@ use function sprintf;
|
||||
class UpdateClientTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
@@ -36,7 +36,7 @@ class UpdateClientTool
|
||||
throw new AccessDeniedException('Access denied: ROLE_ADMIN required.');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->find($id);
|
||||
$client = $this->clientRepository->findById($id);
|
||||
if (null === $client) {
|
||||
throw new InvalidArgumentException(sprintf('Client with ID %d not found.', $id));
|
||||
}
|
||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Module\ProjectManagement\Infrastructure\Mcp\Tool\Project;
|
||||
|
||||
use App\Mcp\Tool\Serializer;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Project;
|
||||
use App\Repository\ClientRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
@@ -20,7 +20,7 @@ class CreateProjectTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
@@ -46,7 +46,7 @@ class CreateProjectTool
|
||||
$project->setColor($color);
|
||||
}
|
||||
if (null !== $clientId) {
|
||||
$client = $this->clientRepository->find($clientId);
|
||||
$client = $this->clientRepository->findById($clientId);
|
||||
if (null === $client) {
|
||||
throw new InvalidArgumentException(sprintf('Client with ID %d not found.', $clientId));
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Module\ProjectManagement\Infrastructure\Mcp\Tool\Project;
|
||||
|
||||
use App\Mcp\Tool\Serializer;
|
||||
use App\Module\Directory\Domain\Repository\ClientRepositoryInterface;
|
||||
use App\Module\ProjectManagement\Domain\Repository\ProjectRepositoryInterface;
|
||||
use App\Repository\ClientRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
@@ -20,7 +20,7 @@ class UpdateProjectTool
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ProjectRepositoryInterface $projectRepository,
|
||||
private readonly ClientRepository $clientRepository,
|
||||
private readonly ClientRepositoryInterface $clientRepository,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
@@ -57,7 +57,7 @@ class UpdateProjectTool
|
||||
$project->setColor($color);
|
||||
}
|
||||
if (null !== $clientId) {
|
||||
$client = $this->clientRepository->find($clientId);
|
||||
$client = $this->clientRepository->findById($clientId);
|
||||
if (null === $client) {
|
||||
throw new InvalidArgumentException(sprintf('Client with ID %d not found.', $clientId));
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Client;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
class ClientRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Client::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user