feat(api) : ajoute pagination et filtres pour les catalogues

This commit is contained in:
2026-01-23 19:35:26 +01:00
parent 7da5eb917a
commit 86447000b1
8 changed files with 180 additions and 137 deletions

View File

@@ -130,15 +130,18 @@ import-data:
# Fixtures management
fixtures-dump:
@echo "Dumping current database to fixtures/data.sql..."
$(DOCKER_COMPOSE) exec -T db pg_dump -U $(POSTGRES_USER) -d $(POSTGRES_DB) --data-only --inserts --no-owner --no-privileges | grep -v "^pg_dump:" | grep -v "^\\\\restrict" > fixtures/data.sql
@echo "Fixtures saved to fixtures/data.sql ($(shell wc -l < fixtures/data.sql) lines)"
$(DOCKER_COMPOSE) exec -T db pg_dump -U $(POSTGRES_USER) -d $(POSTGRES_DB) \
--data-only --inserts --no-owner --no-privileges \
--exclude-table=doctrine_migration_versions \
| grep -v "^pg_dump:" | grep -v "^\\\\restrict" > fixtures/data.sql
@echo "Fixtures saved to fixtures/data.sql"
fixtures-load:
@echo "Loading fixtures from fixtures/data.sql..."
@echo "Loading fixtures from fixtures/data.sql (FK checks disabled)..."
$(DOCKER_COMPOSE) exec -T db psql -U $(POSTGRES_USER) -d $(POSTGRES_DB) -c "SET session_replication_role = replica;"
$(DOCKER_COMPOSE) exec -T db psql -U $(POSTGRES_USER) -d $(POSTGRES_DB) < fixtures/data.sql
-$(DOCKER_COMPOSE) exec -T db psql -U $(POSTGRES_USER) -d $(POSTGRES_DB) < fixtures/data.sql
$(DOCKER_COMPOSE) exec -T db psql -U $(POSTGRES_USER) -d $(POSTGRES_DB) -c "SET session_replication_role = DEFAULT;"
@echo "Fixtures loaded successfully!"
@echo "Fixtures loaded!"
fixtures-reset:
@echo "Resetting database and loading fixtures..."

View File

@@ -4,8 +4,12 @@ declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\ComposantRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -15,8 +19,12 @@ use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity(repositoryClass: ComposantRepository::class)]
#[ORM\Table(name: 'composants')]
#[ORM\HasLifecycleCallbacks]
#[ApiFilter(SearchFilter::class, properties: ['name' => 'partial', 'reference' => 'partial'])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'createdAt'])]
#[ApiResource(
normalizationContext: ['groups' => ['composant:read']],
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class Composant
{
@@ -85,28 +93,28 @@ class Composant
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
#[Groups(['composant:read'])]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
#[Groups(['composant:read'])]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
public function __construct()
{
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->customFieldValues = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$now = new \DateTimeImmutable();
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -114,12 +122,7 @@ class Composant
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
public function getId(): ?string
@@ -262,13 +265,18 @@ class Composant
return $this->customFieldValues;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
private function generateCuid(): string
{
return 'cl'.bin2hex(random_bytes(12));
}
}

View File

@@ -6,6 +6,7 @@ namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\ConstructeurRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -14,7 +15,10 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ConstructeurRepository::class)]
#[ORM\Table(name: 'constructeurs')]
#[ORM\HasLifecycleCallbacks]
#[ApiResource]
#[ApiResource(
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class Constructeur
{
#[ORM\Id]
@@ -31,10 +35,10 @@ class Constructeur
private ?string $phone = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
/**
* @var Collection<int, Machine>
@@ -62,20 +66,20 @@ class Constructeur
public function __construct()
{
$this->machines = new ArrayCollection();
$this->machines = new ArrayCollection();
$this->composants = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->products = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->products = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$now = new \DateTimeImmutable();
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -83,12 +87,7 @@ class Constructeur
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
public function getId(): ?string
@@ -139,13 +138,18 @@ class Constructeur
return $this;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
private function generateCuid(): string
{
return 'cl'.bin2hex(random_bytes(12));
}
}

View File

@@ -9,6 +9,7 @@ use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Enum\ModelCategory;
use App\Repository\ModelTypeRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -20,7 +21,10 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[ORM\UniqueConstraint(name: 'unique_category_name', columns: ['category', 'name'])]
#[ORM\HasLifecycleCallbacks]
#[ApiFilter(SearchFilter::class, properties: ['category' => 'exact'])]
#[ApiResource]
#[ApiResource(
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class ModelType
{
#[ORM\Id]
@@ -62,11 +66,11 @@ class ModelType
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
#[Groups(['model_type:read'])]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
#[Groups(['model_type:read'])]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
private ?array $pendingStructure = null;
@@ -126,25 +130,25 @@ class ModelType
public function __construct()
{
$this->composants = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->products = new ArrayCollection();
$this->composants = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->products = new ArrayCollection();
$this->componentRequirements = new ArrayCollection();
$this->pieceRequirements = new ArrayCollection();
$this->productRequirements = new ArrayCollection();
$this->customFields = new ArrayCollection();
$this->pieceCustomFields = new ArrayCollection();
$this->productCustomFields = new ArrayCollection();
$this->pieceRequirements = new ArrayCollection();
$this->productRequirements = new ArrayCollection();
$this->customFields = new ArrayCollection();
$this->pieceCustomFields = new ArrayCollection();
$this->productCustomFields = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$now = new \DateTimeImmutable();
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -152,12 +156,7 @@ class ModelType
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
public function getId(): ?string
@@ -205,7 +204,7 @@ class ModelType
{
$this->category = $category;
if ($this->pendingStructure !== null) {
if (null !== $this->pendingStructure) {
$this->applyStructureForCategory($this->pendingStructure, $category);
$this->pendingStructure = null;
}
@@ -278,8 +277,8 @@ class ModelType
{
return match ($this->category) {
ModelCategory::COMPONENT => $this->componentSkeleton,
ModelCategory::PIECE => $this->pieceSkeleton,
ModelCategory::PRODUCT => $this->productSkeleton,
ModelCategory::PIECE => $this->pieceSkeleton,
ModelCategory::PRODUCT => $this->productSkeleton,
};
}
@@ -288,6 +287,7 @@ class ModelType
{
if (!isset($this->category)) {
$this->pendingStructure = $structure;
return $this;
}
@@ -296,34 +296,41 @@ class ModelType
return $this;
}
private function applyStructureForCategory(?array $structure, ModelCategory $category): void
{
if ($category === ModelCategory::COMPONENT) {
$this->componentSkeleton = $structure;
$this->pieceSkeleton = null;
$this->productSkeleton = null;
return;
}
if ($category === ModelCategory::PIECE) {
$this->pieceSkeleton = $structure;
$this->componentSkeleton = null;
$this->productSkeleton = null;
return;
}
$this->productSkeleton = $structure;
$this->componentSkeleton = null;
$this->pieceSkeleton = null;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
private function generateCuid(): string
{
return 'cl'.bin2hex(random_bytes(12));
}
private function applyStructureForCategory(?array $structure, ModelCategory $category): void
{
if (ModelCategory::COMPONENT === $category) {
$this->componentSkeleton = $structure;
$this->pieceSkeleton = null;
$this->productSkeleton = null;
return;
}
if (ModelCategory::PIECE === $category) {
$this->pieceSkeleton = $structure;
$this->componentSkeleton = null;
$this->productSkeleton = null;
return;
}
$this->productSkeleton = $structure;
$this->componentSkeleton = null;
$this->pieceSkeleton = null;
}
}

View File

@@ -4,8 +4,12 @@ declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\PieceRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -15,8 +19,12 @@ use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity(repositoryClass: PieceRepository::class)]
#[ORM\Table(name: 'pieces')]
#[ORM\HasLifecycleCallbacks]
#[ApiFilter(SearchFilter::class, properties: ['name' => 'partial', 'reference' => 'partial'])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'createdAt'])]
#[ApiResource(
normalizationContext: ['groups' => ['piece:read']],
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class Piece
{
@@ -81,28 +89,28 @@ class Piece
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
#[Groups(['piece:read'])]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
#[Groups(['piece:read'])]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
public function __construct()
{
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->customFieldValues = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$now = new \DateTimeImmutable();
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -110,12 +118,7 @@ class Piece
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
public function getId(): ?string
@@ -230,13 +233,18 @@ class Piece
return $this->customFieldValues;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
private function generateCuid(): string
{
return 'cl'.bin2hex(random_bytes(12));
}
}

View File

@@ -4,8 +4,12 @@ declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\ProductRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -15,8 +19,12 @@ use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity(repositoryClass: ProductRepository::class)]
#[ORM\Table(name: 'products')]
#[ORM\HasLifecycleCallbacks]
#[ApiFilter(SearchFilter::class, properties: ['name' => 'partial', 'reference' => 'partial'])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'createdAt'])]
#[ApiResource(
normalizationContext: ['groups' => ['product:read']],
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class Product
{
@@ -88,30 +96,30 @@ class Product
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
#[Groups(['product:read'])]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
#[Groups(['product:read'])]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
public function __construct()
{
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->constructeurs = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->customFieldValues = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->composants = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
$this->pieces = new ArrayCollection();
$this->composants = new ArrayCollection();
$this->machineLinks = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$now = new \DateTimeImmutable();
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -119,12 +127,7 @@ class Product
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
public function getId(): ?string
@@ -227,13 +230,18 @@ class Product
return $this->customFieldValues;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
private function generateCuid(): string
{
return 'cl'.bin2hex(random_bytes(12));
}
}

View File

@@ -11,6 +11,7 @@ use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Repository\SiteRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -27,7 +28,9 @@ use Symfony\Component\Validator\Constraints as Assert;
new Post(),
new Put(),
new Delete(),
]
],
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class Site
{
@@ -55,10 +58,10 @@ class Site
private string $contactCity = '';
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
private \DateTimeImmutable $createdAt;
private DateTimeImmutable $createdAt;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
private \DateTimeImmutable $updatedAt;
private DateTimeImmutable $updatedAt;
/**
* @var Collection<int, Machine>
@@ -74,18 +77,18 @@ class Site
public function __construct()
{
$this->machines = new ArrayCollection();
$this->machines = new ArrayCollection();
$this->documents = new ArrayCollection();
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$this->createdAt = new \DateTimeImmutable();
$this->updatedAt = new \DateTimeImmutable();
$this->createdAt = new DateTimeImmutable();
$this->updatedAt = new DateTimeImmutable();
// Générer un ID CUID-compatible si nécessaire
if ($this->id === null) {
if (null === $this->id) {
$this->id = $this->generateCuid();
}
}
@@ -93,13 +96,7 @@ class Site
#[ORM\PreUpdate]
public function setUpdatedAtValue(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
private function generateCuid(): string
{
// Génération d'un ID compatible CUID (format: cl + 24 caractères)
return 'cl' . bin2hex(random_bytes(12));
$this->updatedAt = new DateTimeImmutable();
}
// Getters et Setters
@@ -188,12 +185,12 @@ class Site
return $this;
}
public function getCreatedAt(): \DateTimeImmutable
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
public function getUpdatedAt(): DateTimeImmutable
{
return $this->updatedAt;
}
@@ -257,4 +254,10 @@ class Site
return $this;
}
private function generateCuid(): string
{
// Génération d'un ID compatible CUID (format: cl + 24 caractères)
return 'cl'.bin2hex(random_bytes(12));
}
}

View File

@@ -32,7 +32,9 @@ use Symfony\Component\Validator\Constraints as Assert;
new Post(),
new Put(),
new Delete(),
]
],
paginationClientItemsPerPage: true,
paginationMaximumItemsPerPage: 500
)]
class TypeMachine
{
@@ -118,14 +120,14 @@ class TypeMachine
public function __construct()
{
$this->id = 'cl' . bin2hex(random_bytes(12));
$this->createdAt = new DateTimeImmutable();
$this->updatedAt = new DateTimeImmutable();
$this->machines = new ArrayCollection();
$this->customFields = new ArrayCollection();
$this->id = 'cl'.bin2hex(random_bytes(12));
$this->createdAt = new DateTimeImmutable();
$this->updatedAt = new DateTimeImmutable();
$this->machines = new ArrayCollection();
$this->customFields = new ArrayCollection();
$this->componentRequirements = new ArrayCollection();
$this->pieceRequirements = new ArrayCollection();
$this->productRequirements = new ArrayCollection();
$this->pieceRequirements = new ArrayCollection();
$this->productRequirements = new ArrayCollection();
}
public function getId(): ?string