Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/Services/EDA/KiCadHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public function getKiCADPart(Part $part): array
];

$result["fields"]["footprint"] = $this->createField($part->getEdaInfo()->getKicadFootprint() ?? $part->getFootprint()?->getEdaInfo()->getKicadFootprint() ?? "");
$result["fields"]["reference"] = $this->createField($part->getEdaInfo()->getReferencePrefix() ?? $part->getCategory()?->getEdaInfo()->getReferencePrefix() ?? 'U', true);
$result["fields"]["reference"] = $this->createField($this->getReferencePrefix($part), true);
$result["fields"]["value"] = $this->createField($part->getEdaInfo()->getValue() ?? $part->getName(), true);
$result["fields"]["keywords"] = $this->createField($part->getTags());

Expand Down Expand Up @@ -355,6 +355,36 @@ public function getKiCADPart(Part $part): array
return $result;
}

/**
* Resolve the reference prefix for the given part.
*
* A part without its own reference prefix inherits the prefix of the closest category
* ancestor that defines one (a category tree can be several levels deep, see issue #1535).
* If neither the part nor any category ancestor defines a prefix, 'U' is used as fallback.
*/
private function getReferencePrefix(Part $part): string
{
$prefix = $part->getEdaInfo()->getReferencePrefix();
if ($prefix !== null && $prefix !== '') {
return $prefix;
}

//Walk the category tree upwards: the closest ancestor with a prefix wins.
$category = $part->getCategory();
$depth = 0;
while ($category !== null && $depth < 20) {
$prefix = $category->getEdaInfo()->getReferencePrefix();
if ($prefix !== null && $prefix !== '') {
return $prefix;
}

$category = $category->getParent();
++$depth;
}

return 'U';
}

/**
* Determine if the given part should be visible for the EDA.
* @param Category $category
Expand Down
72 changes: 72 additions & 0 deletions tests/Services/EDA/KiCadHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,78 @@ public function testParameterWithEmptyNameIsSkipped(): void
self::assertArrayNotHasKey('', $result['fields']);
}

public function testReferencePrefixIsInheritedFromAncestorCategory(): void
{
$part = $this->em->find(Part::class, 1);
$part->getEdaInfo()->setReferencePrefix(null);

$parent = (new Category())->setName('Connectors');
$parent->getEdaInfo()->setReferencePrefix('J');

$child = (new Category())->setName('D-sub');
$child->setParent($parent);

$part->setCategory($child);

$result = $this->helper->getKiCADPart($part);

self::assertSame('J', $result['fields']['reference']['value']);
}

public function testNearestCategoryWithPrefixWins(): void
{
$part = $this->em->find(Part::class, 1);
$part->getEdaInfo()->setReferencePrefix(null);

$parent = (new Category())->setName('Connectors');
$parent->getEdaInfo()->setReferencePrefix('J');

$child = (new Category())->setName('D-sub');
$child->getEdaInfo()->setReferencePrefix('X');
$child->setParent($parent);

$part->setCategory($child);

$result = $this->helper->getKiCADPart($part);

self::assertSame('X', $result['fields']['reference']['value']);
}

public function testPartReferencePrefixOverridesCategory(): void
{
$part = $this->em->find(Part::class, 1);
$part->getEdaInfo()->setReferencePrefix('C');

$parent = (new Category())->setName('Connectors');
$parent->getEdaInfo()->setReferencePrefix('J');

$child = (new Category())->setName('D-sub');
$child->setParent($parent);

$part->setCategory($child);

$result = $this->helper->getKiCADPart($part);

self::assertSame('C', $result['fields']['reference']['value']);
}

public function testReferencePrefixFallsBackToUWhenNothingIsSet(): void
{
$part = $this->em->find(Part::class, 1);
$part->getEdaInfo()->setReferencePrefix(null);

$parent = (new Category())->setName('Connectors');

$child = (new Category())->setName('D-sub');
$child->setParent($parent);

$part->setCategory($child);

$result = $this->helper->getKiCADPart($part);

self::assertSame('U', $result['fields']['reference']['value']);
}

/**
* Category 1 (from fixtures) has a KiCad symbol set, so its parts are visible to the EDA.
* The listing must carry the fields, so KiCad does not have to request each part separately.
Expand Down
Loading