From 078f04fe67fa6acece3311088630cad19f0dcb97 Mon Sep 17 00:00:00 2001 From: Sebastian Almberg <83243306+Sebbeben@users.noreply.github.com> Date: Sun, 8 Feb 2026 22:49:09 +0100 Subject: [PATCH] Add CSV import support for EDA/KiCad fields Add user-friendly column aliases (kicad_symbol, kicad_footprint, kicad_reference, kicad_value, eda_exclude_bom, etc.) to the CSV import system. Users can now bulk-set KiCad symbols, footprints, and other EDA metadata via CSV/Excel import without knowing the internal dot notation. --- src/Serializer/PartNormalizer.php | 45 +++++++++++++++++++++++++ tests/Serializer/PartNormalizerTest.php | 40 ++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/Serializer/PartNormalizer.php b/src/Serializer/PartNormalizer.php index 775df77f..8486a634 100644 --- a/src/Serializer/PartNormalizer.php +++ b/src/Serializer/PartNormalizer.php @@ -55,6 +55,15 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface, Norm 'spn' => 'supplier_part_number', 'supplier_product_number' => 'supplier_part_number', 'storage_location' => 'storelocation', + //EDA/KiCad field aliases + 'kicad_symbol' => 'eda_kicad_symbol', + 'kicad_footprint' => 'eda_kicad_footprint', + 'kicad_reference' => 'eda_reference_prefix', + 'kicad_value' => 'eda_value', + 'eda_exclude_bom' => 'eda_exclude_from_bom', + 'eda_exclude_board' => 'eda_exclude_from_board', + 'eda_exclude_sim' => 'eda_exclude_from_sim', + 'eda_invisible' => 'eda_visibility', ]; public function __construct( @@ -190,9 +199,45 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface, Norm } } + //Handle EDA/KiCad fields + $this->applyEdaFields($object, $data); + return $object; } + /** + * Apply EDA/KiCad fields from CSV data to the Part's EDAPartInfo. + */ + private function applyEdaFields(Part $part, array $data): void + { + $edaInfo = $part->getEdaInfo(); + + if (!empty($data['eda_kicad_symbol'])) { + $edaInfo->setKicadSymbol(trim((string) $data['eda_kicad_symbol'])); + } + if (!empty($data['eda_kicad_footprint'])) { + $edaInfo->setKicadFootprint(trim((string) $data['eda_kicad_footprint'])); + } + if (!empty($data['eda_reference_prefix'])) { + $edaInfo->setReferencePrefix(trim((string) $data['eda_reference_prefix'])); + } + if (!empty($data['eda_value'])) { + $edaInfo->setValue(trim((string) $data['eda_value'])); + } + if (isset($data['eda_exclude_from_bom']) && $data['eda_exclude_from_bom'] !== '') { + $edaInfo->setExcludeFromBom(filter_var($data['eda_exclude_from_bom'], FILTER_VALIDATE_BOOLEAN)); + } + if (isset($data['eda_exclude_from_board']) && $data['eda_exclude_from_board'] !== '') { + $edaInfo->setExcludeFromBoard(filter_var($data['eda_exclude_from_board'], FILTER_VALIDATE_BOOLEAN)); + } + if (isset($data['eda_exclude_from_sim']) && $data['eda_exclude_from_sim'] !== '') { + $edaInfo->setExcludeFromSim(filter_var($data['eda_exclude_from_sim'], FILTER_VALIDATE_BOOLEAN)); + } + if (isset($data['eda_visibility']) && $data['eda_visibility'] !== '') { + $edaInfo->setVisibility(filter_var($data['eda_visibility'], FILTER_VALIDATE_BOOLEAN)); + } + } + /** * @return bool[] */ diff --git a/tests/Serializer/PartNormalizerTest.php b/tests/Serializer/PartNormalizerTest.php index 2f07f36d..ac9fcc09 100644 --- a/tests/Serializer/PartNormalizerTest.php +++ b/tests/Serializer/PartNormalizerTest.php @@ -136,4 +136,44 @@ final class PartNormalizerTest extends WebTestCase $this->assertEqualsWithDelta(1.0, $priceDetail->getPriceRelatedQuantity(), PHP_FLOAT_EPSILON); $this->assertEqualsWithDelta(1.0, $priceDetail->getMinDiscountQuantity(), PHP_FLOAT_EPSILON); } + + public function testDenormalizeEdaFields(): void + { + $input = [ + 'name' => 'EDA Test Part', + 'kicad_symbol' => 'Device:R', + 'kicad_footprint' => 'Resistor_SMD:R_0805_2012Metric', + 'kicad_reference' => 'R', + 'kicad_value' => '10k', + 'eda_exclude_bom' => 'true', + 'eda_exclude_board' => 'false', + ]; + + $part = $this->service->denormalize($input, Part::class, 'json', ['groups' => ['import'], 'partdb_import' => true]); + $this->assertInstanceOf(Part::class, $part); + $this->assertSame('EDA Test Part', $part->getName()); + + $edaInfo = $part->getEdaInfo(); + $this->assertSame('Device:R', $edaInfo->getKicadSymbol()); + $this->assertSame('Resistor_SMD:R_0805_2012Metric', $edaInfo->getKicadFootprint()); + $this->assertSame('R', $edaInfo->getReferencePrefix()); + $this->assertSame('10k', $edaInfo->getValue()); + $this->assertTrue($edaInfo->getExcludeFromBom()); + $this->assertFalse($edaInfo->getExcludeFromBoard()); + } + + public function testDenormalizeEdaFieldsEmptyValuesIgnored(): void + { + $input = [ + 'name' => 'Part Without EDA', + 'kicad_symbol' => '', + 'kicad_footprint' => '', + ]; + + $part = $this->service->denormalize($input, Part::class, 'json', ['groups' => ['import'], 'partdb_import' => true]); + + $edaInfo = $part->getEdaInfo(); + $this->assertNull($edaInfo->getKicadSymbol()); + $this->assertNull($edaInfo->getKicadFootprint()); + } }