Files
Ferme/src/Command/SeedCommand.php
tristan 08a17f91b3
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
feat: ajout du prix au kilo et de l'age moyen bovin + feed bovin via xlsx (!50)
| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|                  |                 |

## Description de la PR

## Modification du .env

## Check list

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

Reviewed-on: #50
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-04-28 07:25:31 +00:00

937 lines
34 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Command;
use App\Entity\Address;
use App\Entity\Bovine;
use App\Entity\BovineType;
use App\Entity\Building;
use App\Entity\BuildingCase;
use App\Entity\BuildingCasePosition;
use App\Entity\BuildingLayout;
use App\Entity\Carrier;
use App\Entity\Customer;
use App\Entity\Driver;
use App\Entity\MerchandiseType;
use App\Entity\PelletType;
use App\Entity\ReceptionType;
use App\Entity\ShipmentType;
use App\Entity\Supplier;
use App\Entity\Truck;
use App\Entity\Vehicle;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:seed',
description: 'Seed reference data (idempotent).'
)]
class SeedCommand extends Command
{
private int $created = 0;
private int $updated = 0;
public function __construct(
private readonly EntityManagerInterface $entityManager
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$this->created = 0;
$this->updated = 0;
$trucks = $this->seedTrucks();
$carriers = $this->seedCarriers();
$this->seedDriversAndVehicles($carriers['liot'] ?? null, $trucks['citerne'] ?? null, $trucks['porteur'] ?? null, $io);
$this->seedMerchandiseTypes();
$this->seedPelletTypes();
$this->seedBuildings();
$this->entityManager->flush();
$this->seedBuildingInfrastructure();
$this->entityManager->flush();
$this->seedBovines($io);
$this->seedReceptionTypes();
$this->seedBovineTypes();
$this->seedShipmentTypes();
$this->seedSuppliers();
$this->entityManager->flush();
$this->seedCustomers($io);
$this->entityManager->flush();
$io->success(sprintf('Seed completed: %d created, %d updated.', $this->created, $this->updated));
return Command::SUCCESS;
}
private function seedTrucks(): array
{
$trucks = ['Citerne', 'Porteur', 'Plateau', 'Remorque', 'Benne'];
$citerne = null;
$porteur = null;
foreach ($trucks as $name) {
$truck = $this->upsertByName(Truck::class, $name, static fn (Truck $truck) => $truck->setName($name));
if ('Citerne' === $name) {
$citerne = $truck;
}
if ('Porteur' === $name) {
$porteur = $truck;
}
}
return [
'citerne' => $citerne,
'porteur' => $porteur,
];
}
private function seedCarriers(): array
{
$carriers = [
['name' => 'LIOT', 'code' => 'LIOT'],
['name' => 'LUI-MEME', 'code' => 'LUI-MEME'],
];
$liot = null;
foreach ($carriers as $carrierData) {
$carrier = $this->upsertByCode(Carrier::class, $carrierData['code'], static function (Carrier $carrier) use ($carrierData) {
$carrier
->setName($carrierData['name'])
->setCode($carrierData['code'])
;
});
if ('LIOT' === $carrierData['code']) {
$liot = $carrier;
}
}
return [
'liot' => $liot,
];
}
private function seedDriversAndVehicles(?Carrier $liot, ?Truck $citerne, ?Truck $porteur, SymfonyStyle $io): void
{
if (!$liot || !$citerne || !$porteur) {
$io->warning('Transport data not fully available; drivers/vehicles skipped.');
return;
}
$driverRepo = $this->entityManager->getRepository(Driver::class);
$vehicleRepo = $this->entityManager->getRepository(Vehicle::class);
$drivers = ['Eddy', 'Jean-Christophe', 'Etienne', 'Hersand'];
foreach ($drivers as $name) {
$driver = $driverRepo->findOneBy(['name' => $name, 'carrier' => $liot]);
if (!$driver) {
$driver = new Driver();
++$this->created;
} else {
++$this->updated;
}
$driver
->setName($name)
->setCarrier($liot)
;
$this->entityManager->persist($driver);
}
$vehicles = [
['plate' => 'GH-684-VZ', 'truck' => $citerne],
['plate' => 'FW-363-EC', 'truck' => $porteur],
['plate' => 'FW-370-EC', 'truck' => $porteur],
['plate' => 'FW-375-EC', 'truck' => $porteur],
['plate' => 'FY-952-HS', 'truck' => $porteur],
];
foreach ($vehicles as $vehicleData) {
$vehicle = $vehicleRepo->findOneBy(['plate' => $vehicleData['plate']]);
if (!$vehicle) {
$vehicle = new Vehicle();
++$this->created;
} else {
++$this->updated;
}
$vehicle
->setPlate($vehicleData['plate'])
->setCarrier($liot)
->setTruck($vehicleData['truck'])
;
$this->entityManager->persist($vehicle);
}
}
private function seedMerchandiseTypes(): void
{
$merchandiseTypes = [
['label' => 'Foin', 'code' => 'FOIN'],
['label' => 'Paille', 'code' => 'PAILLE'],
['label' => 'Granule', 'code' => 'GRANULE'],
['label' => 'Autres', 'code' => 'AUTRES'],
];
foreach ($merchandiseTypes as $type) {
$this->upsertByCode(MerchandiseType::class, $type['code'], static function (MerchandiseType $entity) use ($type) {
$entity
->setLabel($type['label'])
->setCode($type['code'])
;
});
}
}
private function seedPelletTypes(): void
{
$pelletTypes = [
['label' => 'JB croissance', 'code' => 'K750'],
['label' => 'Genisse herbe', 'code' => 'K500'],
['label' => 'Bovistart melasse ferme', 'code' => 'K130'],
['label' => 'Bovin mise en forme', 'code' => 'K400'],
];
foreach ($pelletTypes as $type) {
$this->upsertByCode(PelletType::class, $type['code'], static function (PelletType $entity) use ($type) {
$entity
->setLabel($type['label'])
->setCode($type['code'])
;
});
}
}
private function seedBuildings(): void
{
$buildings = [
['label' => 'Bâtiment 1', 'code' => 'B1'],
['label' => 'Bâtiment 2', 'code' => 'B2'],
['label' => 'Bâtiment 3', 'code' => 'B3'],
['label' => 'Zone tampon', 'code' => 'ZT'],
];
foreach ($buildings as $buildingData) {
$this->upsertByCode(Building::class, $buildingData['code'], static function (Building $entity) use ($buildingData) {
$entity
->setLabel($buildingData['label'])
->setCode($buildingData['code'])
;
});
}
}
private function seedBuildingInfrastructure(): void
{
$buildingRepo = $this->entityManager->getRepository(Building::class);
$layoutByBuildingCode = [];
$layoutRows = [
['buildingCode' => 'B1', 'name' => 'plan1', 'columns' => 23, 'rows' => 2],
['buildingCode' => 'B2', 'name' => 'plan2', 'columns' => 23, 'rows' => 2],
['buildingCode' => 'B3', 'name' => 'plan3', 'columns' => 23, 'rows' => 2],
];
foreach ($layoutRows as $layoutRow) {
$building = $buildingRepo->findOneBy(['code' => $layoutRow['buildingCode']]);
if (!$building instanceof Building) {
continue;
}
/** @var BuildingLayout $layout */
$layout = $this->upsertByName(BuildingLayout::class, $layoutRow['name'], static function (BuildingLayout $entity) use ($layoutRow, $building) {
$entity
->setName($layoutRow['name'])
->setColumns($layoutRow['columns'])
->setRows($layoutRow['rows'])
->setIdBuilding($building)
;
});
$layoutByBuildingCode[$layoutRow['buildingCode']] = $layout;
}
$caseRows = [
['buildingCode' => 'B1', 'from' => 1, 'to' => 44],
['buildingCode' => 'B2', 'from' => 1, 'to' => 44],
['buildingCode' => 'B3', 'from' => 1, 'to' => 44],
];
$caseByCode = [];
foreach ($caseRows as $caseRow) {
$building = $buildingRepo->findOneBy(['code' => $caseRow['buildingCode']]);
if (!$building instanceof Building) {
continue;
}
for ($caseNumber = $caseRow['from']; $caseNumber <= $caseRow['to']; ++$caseNumber) {
$code = sprintf('%s-C%d', $caseRow['buildingCode'], $caseNumber);
/** @var BuildingCase $buildingCase */
$buildingCase = $this->upsertByCode(BuildingCase::class, $code, static function (BuildingCase $entity) use ($code, $caseNumber, $building) {
$entity
->setCode($code)
->setCaseNumber($caseNumber)
->setCapacity(15)
->setIdBuilding($building)
;
});
$caseByCode[$code] = $buildingCase;
}
}
$slots = $this->buildSlotMap();
$positionRepo = $this->entityManager->getRepository(BuildingCasePosition::class);
foreach (['B1' => 'plan1', 'B2' => 'plan2', 'B3' => 'plan3'] as $buildingCode => $layoutName) {
$layout = $layoutByBuildingCode[$buildingCode] ?? null;
if (!$layout instanceof BuildingLayout || $layout->getName() !== $layoutName) {
continue;
}
foreach ($slots as $slot) {
$caseCode = sprintf('%s-C%d', $buildingCode, $slot['caseNumber']);
$buildingCase = $caseByCode[$caseCode] ?? null;
if (!$buildingCase instanceof BuildingCase) {
continue;
}
$position = $positionRepo->findOneBy([
'buildingLayout' => $layout,
'buildingCase' => $buildingCase,
'x' => $slot['x'],
'y' => $slot['y'],
]);
if ($position instanceof BuildingCasePosition) {
++$this->updated;
continue;
}
$position = new BuildingCasePosition();
$position
->setX($slot['x'])
->setY($slot['y'])
->setW($slot['w'])
->setH($slot['h'])
->setRenderOrder((string) $slot['renderOrder'])
->setBuildingLayout($layout)
->setBuildingCase($buildingCase)
;
++$this->created;
$this->entityManager->persist($position);
}
}
}
private function seedReceptionTypes(): void
{
$receptionTypes = [
['label' => 'Marchandises', 'code' => 'MARCHANDISES'],
['label' => 'Bovins', 'code' => 'BOVINS'],
];
foreach ($receptionTypes as $type) {
$this->upsertByCode(ReceptionType::class, $type['code'], static function (ReceptionType $entity) use ($type) {
$entity
->setLabel($type['label'])
->setCode($type['code'])
;
});
}
}
private function seedBovines(SymfonyStyle $io): 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'],
];
$bovineRepo = $this->entityManager->getRepository(Bovine::class);
$caseRepo = $this->entityManager->getRepository(BuildingCase::class);
foreach ($rows as [, $legacyCaseId, $nationalNumber, $receivedWeight, $arrivalDate]) {
$buildingCase = $this->resolveBuildingCaseByLegacyId((int) $legacyCaseId);
if (!$buildingCase instanceof BuildingCase) {
$buildingCase = $caseRepo->find((int) $legacyCaseId);
}
if (!$buildingCase instanceof BuildingCase) {
$io->warning(sprintf(
'Bovine %s skipped: building_case token %d not found.',
$nationalNumber,
$legacyCaseId
));
continue;
}
$bovine = $bovineRepo->findOneBy(['nationalNumber' => $nationalNumber]);
if (!$bovine instanceof Bovine) {
$bovine = new Bovine();
++$this->created;
} else {
++$this->updated;
}
$bovine
->setNationalNumber((string) $nationalNumber)
->setBuildingCase($buildingCase)
->setReceivedWeight((int) $receivedWeight)
->setArrivalDate(new DateTimeImmutable((string) $arrivalDate))
;
$this->entityManager->persist($bovine);
}
}
/**
* @return array<int, array{x:int,y:int,w:int,h:int,renderOrder:int,caseNumber:int}>
*/
private function buildSlotMap(): array
{
$slots = [];
for ($column = 1; $column <= 12; ++$column) {
$slots[] = ['x' => $column, 'y' => 1, 'w' => 1, 'h' => 1, 'renderOrder' => $column, 'caseNumber' => $column + 12];
}
for ($column = 14; $column <= 23; ++$column) {
$slots[] = ['x' => $column, 'y' => 1, 'w' => 1, 'h' => 1, 'renderOrder' => $column - 1, 'caseNumber' => $column + 11];
}
for ($column = 1; $column <= 12; ++$column) {
$slots[] = ['x' => $column, 'y' => 2, 'w' => 1, 'h' => 1, 'renderOrder' => 22 + $column, 'caseNumber' => 13 - $column];
}
for ($column = 14; $column <= 23; ++$column) {
$slots[] = ['x' => $column, 'y' => 2, 'w' => 1, 'h' => 1, 'renderOrder' => 21 + $column, 'caseNumber' => 58 - $column];
}
return $slots;
}
private function resolveBuildingCaseByLegacyId(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 = $this->entityManager->getRepository(BuildingCase::class)->findOneBy(['code' => $code]);
return $buildingCase instanceof BuildingCase ? $buildingCase : null;
}
private function seedBovineTypes(): void
{
$bovineTypes = [
['label' => 'Aubrac', 'code' => '14'],
['label' => 'Limousine', 'code' => '34'],
['label' => 'Charolaise', 'code' => '38'],
['label' => 'Croisé', 'code' => '39'],
['label' => 'Parthenaise', 'code' => '71'],
['label' => "Blonde d'aquitaine", 'code' => '79'],
];
foreach ($bovineTypes as $type) {
$this->upsertByCode(BovineType::class, $type['code'], static function (BovineType $entity) use ($type) {
$entity
->setLabel($type['label'])
->setCode($type['code'])
;
});
}
}
private function seedShipmentTypes(): void
{
$shipmentTypes = [
['label' => 'Boucherie', 'code' => 'BDB'],
['label' => 'Équarrissage', 'code' => 'BE'],
];
foreach ($shipmentTypes as $type) {
$this->upsertByCode(ShipmentType::class, $type['code'], static function (ShipmentType $entity) use ($type) {
$entity
->setLabel($type['label'])
->setCode($type['code'])
;
});
}
}
private function seedSuppliers(): void
{
$suppliers = [
[
'name' => 'LIOT',
'email' => 'lpc.contacts@lpc-liot.fr',
'phone' => '05.49.20.09.10',
'addresses' => [
[
'street' => "14 Allée d'Argenson",
'street2' => 'ZI Nord',
'postalCode' => '86100',
'city' => 'CHATELLERAULT',
'countryCode' => 'FR',
],
],
],
[
'name' => 'ARNAULT EURL',
'email' => 'eurl.arnault86@orange.fr',
'phone' => '05.49.02.65.27',
'addresses' => [
[
'street' => 'Moulin du Guéret',
'street2' => 'B.P 30425',
'postalCode' => '86100',
'city' => 'Antran',
'countryCode' => 'FR',
],
],
],
[
'name' => 'EARL DES GONNIERES',
'email' => null,
'phone' => '06.80.14.18.82',
'addresses' => [
[
'street' => "27 Route d'Ingrandes",
'street2' => 'Les Gonnières',
'postalCode' => '86220',
'city' => 'OYRE',
'countryCode' => 'FR',
],
],
],
[
'name' => 'EARL LESIGNY BABY',
'email' => null,
'phone' => '05.49.86.17.95',
'addresses' => [
[
'street' => '2 Lieu Dit Les Bouquins',
'street2' => null,
'postalCode' => '86270',
'city' => 'LESIGNY',
'countryCode' => 'FR',
],
],
],
[
'name' => 'FEDER',
'email' => 'contact@uco-feder.fr',
'phone' => '03.85.24.25.50',
'addresses' => [
[
'street' => 'Molaise',
'street2' => null,
'postalCode' => '71120',
'city' => 'CHAROLLES',
'countryCode' => 'FR',
],
],
],
[
'name' => "GAEC DE L'ESPOIR",
'email' => 'contact@uco-feder.fr',
'phone' => '05.49.86.57.24',
'addresses' => [
[
'street' => 'La Moujonnerie',
'street2' => null,
'postalCode' => '86450',
'city' => 'PLEUMARTIN',
'countryCode' => 'FR',
],
],
],
[
'name' => 'GRAVELEAU',
'email' => 'contact@graveleau-sarl.fr',
'phone' => '05.49.23.51.66',
'addresses' => [
[
'street' => '3, Le Jeu',
'street2' => null,
'postalCode' => '86220',
'city' => 'INGRANDES',
'countryCode' => 'FR',
],
],
],
[
'name' => 'LORTHOLARY',
'email' => 'contact86@lortholarybetail.com',
'phone' => '05.49.52.77.10',
'addresses' => [
[
'street' => 'Ferme de Geniec',
'street2' => null,
'postalCode' => '86550',
'city' => 'MIGNALOUX BEAUVOIR',
'countryCode' => 'FR',
],
],
],
[
'name' => 'NATERA',
'email' => 'contact86@lortholarybetail.com',
'phone' => '05.65.67.89.46',
'addresses' => [
[
'street' => 'Bd des Balquières',
'street2' => 'BP 3220',
'postalCode' => '12032',
'city' => 'RODEZ CEDEX 9',
'countryCode' => 'FR',
],
],
],
[
'name' => 'SCEA DES BARIOLLIÈRES',
'email' => 'elisregnier@gmail.com',
'phone' => '06.09.37.65.61',
'addresses' => [
[
'street' => '2 rue des Barriollières',
'street2' => null,
'postalCode' => '86220',
'city' => 'INGRANDES',
'countryCode' => 'FR',
],
],
],
[
'name' => 'SCEA SENE',
'email' => null,
'phone' => null,
'addresses' => [
[
'street' => '3 Route de la Roche Posay',
'street2' => 'Les Girouettes',
'postalCode' => '86100',
'city' => 'CHATELLERAULT',
'countryCode' => 'FR',
],
],
],
[
'name' => 'TERRENA',
'email' => null,
'phone' => '02.51.67.17.98',
'addresses' => [
[
'street' => 'La Blanchardière',
'street2' => null,
'postalCode' => '44522',
'city' => 'MESANGER',
'countryCode' => 'FR',
],
],
],
[
'name' => 'TRICHERIE COOPERATIVE',
'email' => 'contact@cooptricherie.fr',
'phone' => '05.49.19.44.33',
'addresses' => [
[
'street' => 'B.P n°2',
'street2' => null,
'postalCode' => '86490',
'city' => 'BEAUMONT',
'countryCode' => 'FR',
],
],
],
[
'name' => 'TURPAULT MURIEL',
'email' => null,
'phone' => null,
'addresses' => [
[
'street' => '23Bis Rue Marcel Pagnol',
'street2' => null,
'postalCode' => '86100',
'city' => 'TARGE',
'countryCode' => 'FR',
],
],
],
[
'name' => 'EARL DE LA MENAUDIERE',
'email' => 'frederic.doussineau@orange.fr',
'phone' => '0675446004',
'addresses' => [
[
'street' => '1 la menaudière',
'street2' => null,
'postalCode' => '86450',
'city' => 'LEIGNE LES BOIS ',
'countryCode' => 'FR',
],
],
],
[
'name' => 'SARL ERBS',
'email' => 'touillet.jacques@yahoo.fr',
'phone' => '0675030304',
'addresses' => [
[
'street' => 'les rodières ',
'street2' => null,
'postalCode' => '86230',
'city' => 'Sérigny',
'countryCode' => 'FR',
],
],
],
];
foreach ($suppliers as $supplierData) {
$supplier = $this->upsertByName(Supplier::class, $supplierData['name'], static function (Supplier $supplier) use ($supplierData) {
$supplier
->setName($supplierData['name'])
->setEmail($supplierData['email'])
->setPhone($supplierData['phone'])
;
});
foreach ($supplierData['addresses'] as $addressData) {
$address = $this->upsertAddress($addressData);
if (!$supplier->getAddresses()->contains($address)) {
$supplier->getAddresses()->add($address);
}
}
$this->entityManager->persist($supplier);
}
}
private function seedCustomers(SymfonyStyle $io): void
{
$addressRepo = $this->entityManager->getRepository(Address::class);
$customers = [
[
'name' => 'ARNAULT EURL',
'phone' => '05.49.02.65.27',
'email' => 'eurl.arnault86@orange.fr',
'addresses' => [
[
'street' => 'Moulin du Guéret',
'street2' => 'B.P 30425',
'postalCode' => '86100',
'city' => 'Antran',
'countryCode' => 'FR',
],
],
],
[
'name' => 'COVILIM',
'phone' => '05.55.30.03.10',
'email' => 'sandra.robineaux@covilim.com',
'addresses' => [
[
'street' => 'Rue de Nexon',
'street2' => null,
'postalCode' => '87000',
'city' => 'LIMOGES',
'countryCode' => 'FR',
],
],
],
[
'name' => 'LES PRODUCTEURS DE LA MARCHE (LPM)',
'phone' => '05.55.63.04.53',
'email' => 'f.legalliard@lpmcoop.fr',
'addresses' => [
[
'street' => 'Malonze',
'street2' => null,
'postalCode' => '23300',
'city' => 'LA SOUTERRAINE',
'countryCode' => 'FR',
],
],
],
[
'name' => 'LORTHOLARY BETAIL',
'phone' => '05.49.52.77.10',
'email' => 'contact86@lortholarybetail.com',
'addresses' => [
[
'street' => 'FERME DE GENIEC',
'street2' => null,
'postalCode' => '86550',
'city' => 'MIGNALOUX BEAUVOIR',
'countryCode' => 'FR',
],
],
],
[
'name' => 'TERRENA',
'phone' => '02.40.98.90.00',
'email' => 'scouillaud@terrena.fr',
'addresses' => [
[
'street' => 'LA NOELLE',
'street2' => 'BP 20199',
'postalCode' => '44155',
'city' => 'ANCENIS CEDEX',
'countryCode' => 'FR',
],
],
],
];
foreach ($customers as $customerData) {
$customerName = $customerData['name'] ?? $customerData['label'] ?? null;
if (!$customerName) {
$io->warning('Customer skipped: missing "name".');
continue;
}
$customer = $this->upsertByName(Customer::class, $customerName, static function (Customer $customer) use ($customerData, $customerName) {
$customer
->setName($customerName)
->setPhone($customerData['phone'] ?? null)
->setEmail($customerData['email'] ?? null)
;
});
$addresses = [];
if (isset($customerData['addresses']) && is_array($customerData['addresses'])) {
foreach ($customerData['addresses'] as $addressData) {
$addresses[] = $this->upsertAddress($addressData);
}
} else {
// Backward compatibility for older seed format with address ids.
$addressIds = $customerData['addressIds'] ?? (isset($customerData['addressId']) ? [$customerData['addressId']] : []);
foreach ($addressIds as $addressId) {
$address = $addressRepo->find($addressId);
if (!$address instanceof Address) {
$io->warning(sprintf(
'Customer "%s" skipped address id %d: not found.',
$customerName,
$addressId
));
continue;
}
$addresses[] = $address;
}
}
$customer->setAddresses($addresses);
$this->entityManager->persist($customer);
}
}
private function upsertByCode(string $entityClass, string $code, callable $apply): object
{
$repo = $this->entityManager->getRepository($entityClass);
$entity = $repo->findOneBy(['code' => $code]);
if (!$entity) {
$entity = new $entityClass();
++$this->created;
} else {
++$this->updated;
}
$apply($entity);
$this->entityManager->persist($entity);
return $entity;
}
private function upsertByName(string $entityClass, string $name, callable $apply): object
{
$repo = $this->entityManager->getRepository($entityClass);
$entity = $repo->findOneBy(['name' => $name]);
if (!$entity) {
$entity = new $entityClass();
++$this->created;
} else {
++$this->updated;
}
$apply($entity);
$this->entityManager->persist($entity);
return $entity;
}
private function upsertAddress(array $addressData): Address
{
$addressRepo = $this->entityManager->getRepository(Address::class);
$address = $addressRepo->findOneBy([
'street' => $addressData['street'],
'postalCode' => $addressData['postalCode'],
]);
if (!$address) {
$address = new Address();
++$this->created;
} else {
++$this->updated;
}
$address
->setStreet($addressData['street'])
->setStreet2($addressData['street2'])
->setPostalCode($addressData['postalCode'])
->setCity($addressData['city'])
->setCountryCode($addressData['countryCode'])
;
$this->entityManager->persist($address);
return $address;
}
}