[#278] Plan du site (!33)

| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|        #278          |        Plan du site         |

## Description de la PR
[#278] Plan du site

## Modification du .env

## Check list

- [ ] Pas de régression
- [x] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [ ] CHANGELOG modifié

Co-authored-by: Matteo <matteo@yuno.malio.fr>
Reviewed-on: https://gitea.malio.fr/MALIO-DEV/Ferme/pulls/33
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit is contained in:
tristan
2026-02-25 14:16:11 +00:00
committed by Autin
parent c52f22472d
commit f263a11fe8
31 changed files with 2828 additions and 31 deletions
+2
View File
@@ -20,6 +20,8 @@ class AppFixtures extends Fixture implements DependentFixtureInterface
return [
TransportFixtures::class,
ReferenceFixtures::class,
BuildingInfrastructureFixtures::class,
BovineFixtures::class,
UserFixtures::class,
];
}
+120
View File
@@ -0,0 +1,120 @@
<?php
declare(strict_types=1);
namespace App\DataFixtures;
use App\Entity\Bovine;
use App\Entity\BuildingCase;
use DateTimeImmutable;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class BovineFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$rows = [
[1, 15, '7979580026', 390, '2026-02-25'],
[5, 113, '4405604924', 397, '2025-05-22'],
[4, 113, '4405604944', 375, '2025-05-22'],
[2, 113, '4963291114', 319, '2025-05-22'],
[3, 113, '4405604922', 386, '2025-05-22'],
[6, 126, '4415811026', 367, '2025-07-02'],
[7, 126, '4950971149', 398, '2025-07-02'],
[8, 126, '4950971170', 386, '2025-07-02'],
[9, 126, '4489751630', 408, '2025-07-02'],
[10, 126, '8551323003', 478, '2025-07-02'],
[11, 126, '8503833703', 378, '2025-07-02'],
[12, 126, '4402104572', 379, '2025-07-02'],
[13, 126, '4402104580', 465, '2025-07-02'],
[14, 126, '4402104607', 381, '2025-07-02'],
[15, 126, '8504059581', 446, '2025-07-02'],
[16, 124, '4950971161', 382, '2025-07-02'],
[17, 124, '5652911499', 376, '2025-07-02'],
[18, 124, '8551323029', 414, '2025-07-02'],
[19, 124, '4402104590', 474, '2025-07-02'],
[20, 124, '4402104594', 408, '2025-07-02'],
[21, 124, '4402104595', 399, '2025-07-02'],
[22, 124, '4402104604', 374, '2025-07-02'],
[23, 124, '8504059579', 403, '2025-07-02'],
[24, 124, '8504059590', 398, '2025-07-02'],
[25, 123, '8551782070', 395, '2025-07-02'],
[26, 123, '8551782080', 443, '2025-07-02'],
[27, 123, '8551782084', 394, '2025-07-02'],
[28, 123, '8551782090', 378, '2025-07-02'],
[29, 123, '8551782092', 424, '2025-07-02'],
[30, 123, '8551782094', 389, '2025-07-02'],
[31, 123, '8551782099', 411, '2025-07-02'],
[32, 123, '8551323020', 392, '2025-07-02'],
[33, 123, '8551323051', 371, '2025-07-02'],
[34, 123, '7947673148', 378, '2025-07-02'],
[39, 114, '1731177447', 395, '2025-06-19'],
[42, 114, '1726167608', 299, '2025-06-19'],
[38, 114, '1731177442', 343, '2025-06-19'],
[40, 114, '1731177448', 362, '2025-06-19'],
[41, 114, '1731177458', 359, '2025-06-19'],
[35, 114, '7946282100', 291, '2025-06-19'],
[43, 114, '1726167613', 339, '2025-06-19'],
[37, 114, '1731177427', 375, '2025-06-19'],
[36, 114, '7946282103', 354, '2025-06-19'],
];
$bovineRepository = $manager->getRepository(Bovine::class);
$caseRepository = $manager->getRepository(BuildingCase::class);
foreach ($rows as [, $legacyCaseId, $nationalNumber, $receivedWeight, $arrivalDate]) {
$buildingCase = $this->resolveBuildingCaseByLegacyId($manager, (int) $legacyCaseId);
if (!$buildingCase instanceof BuildingCase) {
$buildingCase = $caseRepository->find((int) $legacyCaseId);
}
if (!$buildingCase instanceof BuildingCase) {
continue;
}
/** @var null|Bovine $bovine */
$bovine = $bovineRepository->findOneBy(['nationalNumber' => (string) $nationalNumber]);
if (!$bovine instanceof Bovine) {
$bovine = new Bovine();
}
$bovine
->setNationalNumber((string) $nationalNumber)
->setBuildingCase($buildingCase)
->setReceivedWeight((int) $receivedWeight)
->setArrivalDate(new DateTimeImmutable((string) $arrivalDate))
;
$manager->persist($bovine);
}
$manager->flush();
}
public function getDependencies(): array
{
return [
BuildingInfrastructureFixtures::class,
];
}
private function resolveBuildingCaseByLegacyId(ObjectManager $manager, int $legacyCaseId): ?BuildingCase
{
if ($legacyCaseId < 1) {
return null;
}
$buildingNumber = intdiv($legacyCaseId - 1, 44) + 1;
$caseNumber = (($legacyCaseId - 1) % 44) + 1;
if ($buildingNumber < 1 || $buildingNumber > 3) {
return null;
}
$code = sprintf('B%d-C%d', $buildingNumber, $caseNumber);
$buildingCase = $manager->getRepository(BuildingCase::class)->findOneBy(['code' => $code]);
return $buildingCase instanceof BuildingCase ? $buildingCase : null;
}
}
@@ -0,0 +1,299 @@
<?php
declare(strict_types=1);
namespace App\DataFixtures;
use App\Entity\Building;
use App\Entity\BuildingCase;
use App\Entity\BuildingCasePosition;
use App\Entity\BuildingLayout;
use App\Entity\Statut;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use RuntimeException;
class BuildingInfrastructureFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$statuts = $this->loadStatuts($manager);
$buildings = $this->getBuildingsByCode($manager, ['B1', 'B2', 'B3']);
$layouts = $this->loadLayouts($manager, $buildings);
$cases = $this->loadBuildingCases($manager, $buildings, $statuts);
$this->loadCasePositions($manager, $layouts, $cases);
$manager->flush();
}
public function getDependencies(): array
{
return [
ReferenceFixtures::class,
];
}
/**
* @return array<string, Statut>
*/
private function loadStatuts(ObjectManager $manager): array
{
$repo = $manager->getRepository(Statut::class);
$data = [
['label' => 'Libre', 'code' => 'LB', 'color' => '#A3B18A'],
['label' => 'Occupé', 'code' => 'OC', 'color' => '#3A506B'],
['label' => 'Malade', 'code' => 'ML', 'color' => '#E07A5F'],
];
$result = [];
foreach ($data as $row) {
/** @var null|Statut $statut */
$statut = $repo->findOneBy(['code' => $row['code']]);
if (!$statut instanceof Statut) {
$statut = new Statut()
->setLabel($row['label'])
->setCode($row['code'])
->setColor($row['color'])
;
$manager->persist($statut);
}
$result[$row['code']] = $statut;
}
return $result;
}
/**
* @param list<string> $codes
*
* @return array<string, Building>
*/
private function getBuildingsByCode(ObjectManager $manager, array $codes): array
{
$repo = $manager->getRepository(Building::class);
$result = [];
foreach ($codes as $code) {
/** @var null|Building $building */
$building = $repo->findOneBy(['code' => $code]);
if (!$building instanceof Building) {
throw new RuntimeException(sprintf('Building "%s" not found. Load ReferenceFixtures first.', $code));
}
$result[$code] = $building;
}
return $result;
}
/**
* @param array<string, Building> $buildings
*
* @return array<string, BuildingLayout>
*/
private function loadLayouts(ObjectManager $manager, array $buildings): array
{
$repo = $manager->getRepository(BuildingLayout::class);
$data = [
['name' => 'plan1', 'columns' => 23, 'rows' => 2, 'buildingCode' => 'B1'],
['name' => 'plan2', 'columns' => 23, 'rows' => 2, 'buildingCode' => 'B2'],
['name' => 'plan3', 'columns' => 23, 'rows' => 2, 'buildingCode' => 'B3'],
];
$result = [];
foreach ($data as $row) {
/** @var null|BuildingLayout $layout */
$layout = $repo->findOneBy(['name' => $row['name']]);
if (!$layout instanceof BuildingLayout) {
$layout = new BuildingLayout()
->setName($row['name'])
->setColumns($row['columns'])
->setRows($row['rows'])
->setIdBuilding($buildings[$row['buildingCode']])
;
$manager->persist($layout);
}
$result[$row['buildingCode']] = $layout;
}
return $result;
}
/**
* @param array<string, Building> $buildings
* @param array<string, Statut> $statuts
*
* @return array<string, BuildingCase>
*/
private function loadBuildingCases(ObjectManager $manager, array $buildings, array $statuts): array
{
$repo = $manager->getRepository(BuildingCase::class);
$statusRanges = [
// B1
['buildingCode' => 'B1', 'from' => 1, 'to' => 12, 'statut' => 'LB'],
['buildingCode' => 'B1', 'from' => 13, 'to' => 24, 'statut' => 'OC'],
['buildingCode' => 'B1', 'from' => 25, 'to' => 32, 'statut' => 'ML'],
['buildingCode' => 'B1', 'from' => 33, 'to' => 44, 'statut' => 'LB'],
// B2
['buildingCode' => 'B2', 'from' => 1, 'to' => 10, 'statut' => 'OC'],
['buildingCode' => 'B2', 'from' => 11, 'to' => 22, 'statut' => 'LB'],
['buildingCode' => 'B2', 'from' => 23, 'to' => 30, 'statut' => 'ML'],
['buildingCode' => 'B2', 'from' => 31, 'to' => 44, 'statut' => 'OC'],
// B3
['buildingCode' => 'B3', 'from' => 1, 'to' => 8, 'statut' => 'ML'],
['buildingCode' => 'B3', 'from' => 9, 'to' => 20, 'statut' => 'LB'],
['buildingCode' => 'B3', 'from' => 21, 'to' => 34, 'statut' => 'OC'],
['buildingCode' => 'B3', 'from' => 35, 'to' => 44, 'statut' => 'ML'],
];
$result = [];
foreach ($statusRanges as $range) {
for ($caseNumber = $range['from']; $caseNumber <= $range['to']; ++$caseNumber) {
$code = sprintf('%s-C%d', $range['buildingCode'], $caseNumber);
if (isset($result[$code])) {
continue;
}
/** @var null|BuildingCase $buildingCase */
$buildingCase = $repo->findOneBy(['code' => $code]);
if (!$buildingCase instanceof BuildingCase) {
$buildingCase = new BuildingCase()
->setCaseNumber($caseNumber)
->setCode($code)
->setCapacity(15)
->setIdBuilding($buildings[$range['buildingCode']])
->setStatut($statuts[$range['statut']])
;
$manager->persist($buildingCase);
}
$result[$code] = $buildingCase;
}
}
return $result;
}
/**
* @param array<string, BuildingLayout> $layouts
* @param array<string, BuildingCase> $casesByCode
*/
private function loadCasePositions(ObjectManager $manager, array $layouts, array $casesByCode): void
{
$repo = $manager->getRepository(BuildingCasePosition::class);
$layoutMap = [
'B1' => 'plan1',
'B2' => 'plan2',
'B3' => 'plan3',
];
$slots = $this->buildSlotMap();
foreach ($layoutMap as $buildingCode => $layoutName) {
$layout = $layouts[$buildingCode] ?? null;
if (!$layout instanceof BuildingLayout || $layout->getName() !== $layoutName) {
throw new RuntimeException(sprintf('Layout "%s" for building "%s" not found.', $layoutName, $buildingCode));
}
foreach ($slots as $slot) {
$caseCode = sprintf('%s-C%d', $buildingCode, $slot['caseNumber']);
$buildingCase = $casesByCode[$caseCode] ?? null;
if (!$buildingCase instanceof BuildingCase) {
throw new RuntimeException(sprintf('Building case "%s" not found.', $caseCode));
}
/** @var null|BuildingCasePosition $position */
$position = $repo->findOneBy([
'buildingLayout' => $layout,
'buildingCase' => $buildingCase,
'x' => $slot['x'],
'y' => $slot['y'],
]);
if ($position instanceof BuildingCasePosition) {
continue;
}
$position = new BuildingCasePosition()
->setX($slot['x'])
->setY($slot['y'])
->setW($slot['w'])
->setH($slot['h'])
->setRenderOrder((string) $slot['renderOrder'])
->setBuildingLayout($layout)
->setBuildingCase($buildingCase)
;
$manager->persist($position);
}
}
}
/**
* Reproduit le slot_map SQL (44 emplacements sur 2 lignes avec un gap en colonne 13).
*
* @return list<array{x:int,y:int,w:int,h:int,renderOrder:int,caseNumber:int}>
*/
private function buildSlotMap(): array
{
$slots = [];
// Ligne 1, colonnes 1..12 => cases 13..24
for ($c = 1; $c <= 12; ++$c) {
$slots[] = [
'x' => $c,
'y' => 1,
'w' => 1,
'h' => 1,
'renderOrder' => $c,
'caseNumber' => $c + 12,
];
}
// Ligne 1, colonnes 14..23 => cases 25..34
for ($c = 14; $c <= 23; ++$c) {
$slots[] = [
'x' => $c,
'y' => 1,
'w' => 1,
'h' => 1,
'renderOrder' => $c - 1,
'caseNumber' => $c + 11,
];
}
// Ligne 2, colonnes 1..12 => cases 12..1
for ($c = 1; $c <= 12; ++$c) {
$slots[] = [
'x' => $c,
'y' => 2,
'w' => 1,
'h' => 1,
'renderOrder' => 22 + $c,
'caseNumber' => 13 - $c,
];
}
// Ligne 2, colonnes 14..23 => cases 44..35
for ($c = 14; $c <= 23; ++$c) {
$slots[] = [
'x' => $c,
'y' => 2,
'w' => 1,
'h' => 1,
'renderOrder' => 21 + $c,
'caseNumber' => 58 - $c,
];
}
return $slots;
}
}