Part-DB-server/src/Services/EDA/KiCadHelper.php

515 lines
22 KiB
PHP
Raw Normal View History

<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\EDA;
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
use App\Entity\Attachments\Attachment;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Part;
2023-11-29 20:49:16 +01:00
use App\Services\Cache\ElementCacheTagGenerator;
use App\Services\EntityURLGenerator;
use App\Services\Trees\NodesListBuilder;
use App\Settings\MiscSettings\KiCadEDASettings;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class KiCadHelper
{
/** @var int The maximum level of the shown categories. 0 Means only the top level categories are shown. -1 means only a single one containing */
private readonly int $category_depth;
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
/** @var bool Whether to resolve actual datasheet PDF URLs (true) or use Part-DB page links (false) */
private readonly bool $datasheetAsPdf;
public function __construct(
private readonly NodesListBuilder $nodesListBuilder,
private readonly TagAwareCacheInterface $kicadCache,
private readonly EntityManagerInterface $em,
2023-11-29 20:49:16 +01:00
private readonly ElementCacheTagGenerator $tagGenerator,
private readonly UrlGeneratorInterface $urlGenerator,
private readonly EntityURLGenerator $entityURLGenerator,
private readonly TranslatorInterface $translator,
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
private readonly KiCadEDASettings $kiCadEDASettings,
) {
$this->category_depth = $kiCadEDASettings->categoryDepth;
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
$this->datasheetAsPdf = $kiCadEDASettings->datasheetAsPdf ?? true;
}
/**
* Returns an array of objects containing all categories in the database in the format required by KiCAD.
* The categories are flattened and sorted by their full path.
* Categories, which contain no parts, are filtered out.
* The result is cached for performance and invalidated on category changes.
* @return array
*/
public function getCategories(): array
{
return $this->kicadCache->get('kicad_categories_' . $this->category_depth, function (ItemInterface $item) {
//Invalidate the cache on category changes
2023-11-29 20:49:16 +01:00
$secure_class_name = $this->tagGenerator->getElementTypeCacheTag(Category::class);
$item->tag($secure_class_name);
//Invalidate the cache on part changes (as the visibility depends on parts, and the parts can change)
$secure_class_name = $this->tagGenerator->getElementTypeCacheTag(Part::class);
$item->tag($secure_class_name);
//If the category depth is smaller than 0, create only one dummy category
if ($this->category_depth < 0) {
return [
[
'id' => '0',
'name' => 'Part-DB',
]
];
}
//Otherwise just get the categories and filter them
$categories = $this->nodesListBuilder->typeToNodesList(Category::class);
$repo = $this->em->getRepository(Category::class);
$result = [];
foreach ($categories as $category) {
//Skip invisible categories
if ($category->getEdaInfo()->getVisibility() === false) {
continue;
}
//Skip categories with a depth greater than the configured one
if ($category->getLevel() > $this->category_depth) {
continue;
}
//Ensure that the category contains parts
//For the last level, we need to use a recursive query, otherwise we can use a simple query
2023-12-03 15:11:06 +01:00
/** @var Category $category */
$parts_count = $category->getLevel() >= $this->category_depth ? $repo->getPartsCountRecursive($category) : $repo->getPartsCount($category);
if ($parts_count < 1) {
continue;
}
//Check if the category should be visible
if (!$this->shouldCategoryBeVisible($category)) {
continue;
}
//Format the category for KiCAD
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
// Use the category comment as description if available, otherwise use the Part-DB URL
$description = $category->getComment();
if ($description === null || $description === '') {
$description = $this->entityURLGenerator->listPartsURL($category);
}
$result[] = [
'id' => (string)$category->getId(),
'name' => $category->getFullPath('/'),
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
'description' => $description,
];
}
return $result;
});
}
/**
* Returns an array of objects containing all parts for the given category in the format required by KiCAD.
* The result is cached for performance and invalidated on category or part changes.
* @param Category|null $category
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
* @param bool $minimal If true, only return id and name (faster for symbol chooser listing)
* @return array
*/
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
public function getCategoryParts(?Category $category, bool $minimal = false): array
{
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
$cacheKey = 'kicad_category_parts_'.($category?->getID() ?? 0) . '_' . $this->category_depth . ($minimal ? '_min' : '');
return $this->kicadCache->get($cacheKey,
function (ItemInterface $item) use ($category) {
$item->tag([
$this->tagGenerator->getElementTypeCacheTag(Category::class),
$this->tagGenerator->getElementTypeCacheTag(Part::class),
//Visibility can change based on the footprint
$this->tagGenerator->getElementTypeCacheTag(Footprint::class)
]);
if ($this->category_depth >= 0) {
//Ensure that the category is set
2024-06-22 00:31:43 +02:00
if ($category === null) {
throw new NotFoundHttpException('Category must be set, if category_depth is greater than 1!');
}
$category_repo = $this->em->getRepository(Category::class);
if ($category->getLevel() >= $this->category_depth) {
//Get all parts for the category and its children
$parts = $category_repo->getPartsRecursive($category);
} else {
//Get only direct parts for the category (without children), as the category is not collapsed
$parts = $category_repo->getParts($category);
}
} else {
//Get all parts
$parts = $this->em->getRepository(Part::class)->findAll();
}
$result = [];
foreach ($parts as $part) {
//If the part is invisible, then skip it
if (!$this->shouldPartBeVisible($part)) {
continue;
}
$result[] = [
'id' => (string)$part->getId(),
'name' => $part->getName(),
'description' => $part->getDescription(),
];
}
return $result;
});
}
public function getKiCADPart(Part $part): array
{
$result = [
'id' => (string)$part->getId(),
'name' => $part->getName(),
"symbolIdStr" => $part->getEdaInfo()->getKicadSymbol() ?? $part->getCategory()?->getEdaInfo()->getKicadSymbol() ?? "",
"exclude_from_bom" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBom() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBom() ?? false),
"exclude_from_board" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBoard() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBoard() ?? false),
"exclude_from_sim" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromSim() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromSim() ?? false),
"fields" => []
];
$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"]["value"] = $this->createField($part->getEdaInfo()->getValue() ?? $part->getName(), true);
$result["fields"]["keywords"] = $this->createField($part->getTags());
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Use the part info page as Part-DB link. It must be an absolute URL.
$partUrl = $this->urlGenerator->generate(
'part_info',
['id' => $part->getId()],
UrlGeneratorInterface::ABSOLUTE_URL
);
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Try to find an actual datasheet attachment (configurable: PDF URL vs Part-DB page link)
if ($this->datasheetAsPdf) {
$datasheetUrl = $this->findDatasheetUrl($part);
$result["fields"]["datasheet"] = $this->createField($datasheetUrl ?? $partUrl);
} else {
$result["fields"]["datasheet"] = $this->createField($partUrl);
}
$result["fields"]["Part-DB URL"] = $this->createField($partUrl);
//Add basic fields
$result["fields"]["description"] = $this->createField($part->getDescription());
2024-06-22 00:31:43 +02:00
if ($part->getCategory() !== null) {
$result["fields"]["Category"] = $this->createField($part->getCategory()->getFullPath('/'));
}
2024-06-22 00:31:43 +02:00
if ($part->getManufacturer() !== null) {
$result["fields"]["Manufacturer"] = $this->createField($part->getManufacturer()->getName());
}
if ($part->getManufacturerProductNumber() !== "") {
$result['fields']["MPN"] = $this->createField($part->getManufacturerProductNumber());
}
2024-06-22 00:31:43 +02:00
if ($part->getManufacturingStatus() !== null) {
$result["fields"]["Manufacturing Status"] = $this->createField(
//Always use the english translation
$this->translator->trans($part->getManufacturingStatus()->toTranslationKey(), locale: 'en')
);
}
2024-06-22 00:31:43 +02:00
if ($part->getFootprint() !== null) {
$result["fields"]["Part-DB Footprint"] = $this->createField($part->getFootprint()->getName());
}
2024-06-22 00:31:43 +02:00
if ($part->getPartUnit() !== null) {
$unit = $part->getPartUnit()->getName();
if ($part->getPartUnit()->getUnit() !== "") {
$unit .= ' ('.$part->getPartUnit()->getUnit().')';
}
$result["fields"]["Part-DB Unit"] = $this->createField($unit);
}
if ($part->getPartCustomState() !== null) {
$customState = $part->getPartCustomState()->getName();
$result["fields"]["Part-DB Custom state"] = $this->createField($customState);
}
if ($part->getMass()) {
$result["fields"]["Mass"] = $this->createField($part->getMass() . ' g');
}
$result["fields"]["Part-DB ID"] = $this->createField($part->getId());
2024-06-22 00:31:43 +02:00
if ($part->getIpn() !== null && $part->getIpn() !== '' && $part->getIpn() !== '0') {
$result["fields"]["Part-DB IPN"] = $this->createField($part->getIpn());
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Add KiCost manufacturer fields (always present, independent of orderdetails)
if ($part->getManufacturer() !== null) {
$result["fields"]["manf"] = $this->createField($part->getManufacturer()->getName());
}
if ($part->getManufacturerProductNumber() !== "") {
$result['fields']['manf#'] = $this->createField($part->getManufacturerProductNumber());
}
// Add supplier information from orderdetails (include obsolete orderdetails)
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
// If any orderdetail has eda_visibility explicitly set to true, only export those;
// otherwise export all (backward compat when no flags are set)
$allOrderdetails = $part->getOrderdetails(false);
if ($allOrderdetails->count() > 0) {
$hasExplicitEdaVisibility = false;
foreach ($allOrderdetails as $od) {
if ($od->isEdaVisibility() !== null) {
$hasExplicitEdaVisibility = true;
break;
}
}
$supplierCounts = [];
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
foreach ($allOrderdetails as $orderdetail) {
if ($orderdetail->getSupplier() !== null && $orderdetail->getSupplierPartNr() !== '') {
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
// When explicit flags exist, filter by resolved visibility
$resolvedVisibility = $orderdetail->isEdaVisibility() ?? $this->kiCadEDASettings->defaultOrderdetailsVisibility;
if ($hasExplicitEdaVisibility && !$resolvedVisibility) {
continue;
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
$supplierName = $orderdetail->getSupplier()->getName() . ' SPN';
if (!isset($supplierCounts[$supplierName])) {
$supplierCounts[$supplierName] = 0;
}
$supplierCounts[$supplierName]++;
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
// Create field name with sequential number if more than one from same supplier
$fieldName = $supplierCounts[$supplierName] > 1
? $supplierName . ' ' . $supplierCounts[$supplierName]
: $supplierName;
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
$result["fields"][$fieldName] = $this->createField($orderdetail->getSupplierPartNr());
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Also add a KiCost-compatible field (supplier_name# = SPN)
$kicostFieldName = mb_strtolower($orderdetail->getSupplier()->getName()) . '#';
$result["fields"][$kicostFieldName] = $this->createField($orderdetail->getSupplierPartNr());
}
}
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Add stock quantity and storage locations (only count non-expired lots with known quantity)
$totalStock = 0;
$locations = [];
foreach ($part->getPartLots() as $lot) {
$isAvailable = !$lot->isInstockUnknown() && $lot->isExpired() !== true;
if ($isAvailable) {
$totalStock += $lot->getAmount();
if ($lot->getAmount() > 0 && $lot->getStorageLocation() !== null) {
$locations[] = $lot->getStorageLocation()->getName();
}
}
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
$result['fields']['Stock'] = $this->createField($totalStock);
if ($locations !== []) {
$result['fields']['Storage Location'] = $this->createField(implode(', ', array_unique($locations)));
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
//Add parameters marked for EDA export (explicit true, or system default when null)
foreach ($part->getParameters() as $parameter) {
$paramVisibility = $parameter->isEdaVisibility() ?? $this->kiCadEDASettings->defaultParameterVisibility;
if ($paramVisibility && $parameter->getName() !== '') {
$fieldName = $parameter->getName();
//Don't overwrite hardcoded fields
if (!isset($result['fields'][$fieldName])) {
$result['fields'][$fieldName] = $this->createField($parameter->getFormattedValue());
}
}
}
return $result;
}
/**
* Determine if the given part should be visible for the EDA.
* @param Category $category
* @return bool
*/
private function shouldCategoryBeVisible(Category $category): bool
{
$eda_info = $category->getEdaInfo();
//If the category visibility is explicitly set, then use it
if ($eda_info->getVisibility() !== null) {
return $eda_info->getVisibility();
}
//try to check if the fields were set
if ($eda_info->getKicadSymbol() !== null
|| $eda_info->getReferencePrefix() !== null) {
return true;
}
//Check if there is any part in this category, which should be visible
$category_repo = $this->em->getRepository(Category::class);
if ($category->getLevel() >= $this->category_depth) {
//Get all parts for the category and its children
$parts = $category_repo->getPartsRecursive($category);
} else {
//Get only direct parts for the category (without children), as the category is not collapsed
$parts = $category_repo->getParts($category);
}
foreach ($parts as $part) {
if ($this->shouldPartBeVisible($part)) {
return true;
}
}
//Otherwise the category should be not visible
return false;
}
/**
* Determine if the given part should be visible for the EDA.
* @param Part $part
* @return bool
*/
private function shouldPartBeVisible(Part $part): bool
{
$eda_info = $part->getEdaInfo();
$category = $part->getCategory();
//If the user set a visibility, then use it
if ($eda_info->getVisibility() !== null) {
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
return $eda_info->getVisibility();
}
//If the part has a category, then use the category visibility if possible
if ($category && $category->getEdaInfo()->getVisibility() !== null) {
return $category->getEdaInfo()->getVisibility();
}
//If both are null, then we try to determine the visibility based on if fields are set
if ($eda_info->getKicadSymbol() !== null
|| $eda_info->getKicadFootprint() !== null
|| $eda_info->getReferencePrefix() !== null
|| $eda_info->getValue() !== null) {
return true;
}
//Check also if the fields are set for the category (if it exists)
if ($category && (
$category->getEdaInfo()->getKicadSymbol() !== null
|| $category->getEdaInfo()->getReferencePrefix() !== null
)) {
return true;
}
//And on the footprint
//Otherwise the part should be not visible
2024-06-22 00:31:43 +02:00
return $part->getFootprint() && $part->getFootprint()->getEdaInfo()->getKicadFootprint() !== null;
}
/**
* Converts a boolean value to the format required by KiCAD.
* @param bool $value
* @return string
*/
private function boolToKicadBool(bool $value): string
{
return $value ? 'True' : 'False';
}
/**
* Creates a field array for KiCAD
* @param string|int|float $value
* @param bool $visible
* @return array
*/
private function createField(string|int|float $value, bool $visible = false): array
{
return [
'value' => (string)$value,
'visible' => $this->boolToKicadBool($visible),
];
}
Enhance KiCad integration: API v2, batch EDA editing, field export control (#1241) * Add stock quantity, datasheet URL, and HTTP caching to KiCad API - Add Stock field showing total available quantity across all part lots - Add Storage Location field when parts have stored locations - Resolve actual datasheet PDF from attachments (by type name, attachment name, or first PDF) instead of always linking to Part-DB page - Keep Part-DB page URL as separate "Part-DB URL" field - Add ETag and Cache-Control headers to all KiCad API endpoints - Support conditional requests (If-None-Match) returning 304 - Categories/part lists cached 5 min, part details cached 1 min * Add KiCadHelper unit tests and fix PDF detection for external URLs - Add comprehensive KiCadHelperTest with 14 test cases covering: - Stock quantity calculation (zero, single lot, multiple lots) - Stock exclusion of expired and unknown-quantity lots - Storage location display (present, absent, multiple) - Datasheet URL resolution by type name, attachment name, PDF extension - Datasheet fallback to Part-DB URL when no match - "Data sheet" (with space) name variant matching - Fix PDF extension detection for external attachments (getExtension() returns null for external-only attachments, now also parses URL path) * Fix 304 response body, parse_url safety, and location/stock consistency - Use empty Response instead of JsonResponse(null) for 304 Not Modified to avoid sending "null" as response body - Guard parse_url() result with is_string() since it can return false for malformed URLs - Move storage location tracking inside the availability check so expired and unknown-quantity lots don't contribute locations * Fix testPartDetailsPart2 to actually test Part 2 The test was requesting /parts/1.json instead of /parts/2.json and had Part 1's expected data. Now tests Part 2 which inherits EDA info from its category and footprint, verifying the inheritance behavior. * Use Symfony's built-in ETag handling for HTTP caching Replace manual If-None-Match comparison with Response::setEtag() and Response::isNotModified(), which properly handles ETag quoting, weak vs strong comparison, and 304 response cleanup. Fixes PHPStan return type error and CI test failures. * Add configurable KiCad field export for part parameters Add a kicad_export checkbox to parameters, allowing users to control which specifications appear as fields in the KiCad HTTP library API. Parameters with kicad_export enabled are included using their formatted value, without overwriting hardcoded fields like description or Stock. * Add partdb:kicad:populate command for bulk KiCad path assignment Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries. * 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. * Add batch EDA field editing from parts table Users can now select multiple parts in any parts table and batch-edit their EDA/KiCad fields (symbol, footprint, reference prefix, value, visibility, exclude from BOM/board/sim). Each field has an "Apply" checkbox so users control exactly which fields are changed. * Remove unused counter variable in BatchEdaController * Fix PHPStan errors in PopulateKicadCommand and BatchEdaController Add @var type annotations for Doctrine repository findAll() calls so PHPStan can resolve getEdaInfo() on Footprint/Category entities. Fix array return type for numeric-string keys and add explicit callback to array_filter to satisfy strict rules. * Fix batch EDA edit: required validation and pre-populate shared values - Add required=false to TriStateCheckboxType fields so HTML5 validation doesn't force users to check visibility/BOM/board checkboxes - Pre-populate form fields when all selected parts share the same EDA value, so users can see current state before editing * Add KiCad API v2, orderdetail export control, EDA status indicator, BOM improvements - Add KiCad API v2 endpoints (/kicad-api/v2) with volatile field support for stock and storage location (shown but not saved to schematic) - Add kicad_export flag to Orderdetail entity for per-supplier SPN control (backward compatible: if no flag set, all SPNs exported as before) - Add EDA completeness indicator column in parts datatable (bolt icon) - Add ?minimal=true query param for faster category parts loading - Improve category descriptions (use comment instead of URL when available) - Improve BOM importer multi-footprint support: merge entries by Part-DB part ID when linked, tracking footprint variants in comments - Fix KiCost manf/manf# fields always present (not conditional on orderdetails) - Fix duplicate getEdaInfo() call in shouldPartBeVisible - Consolidate supplier SPN and KiCost field generation into single loop * Fix kicad_export column default for SQLite compatibility Add options default to ORM column definition so schema:update works correctly on SQLite test databases. * Make EDA status bolt icon clickable to open EDA settings tab * Fix EDA bolt link to correctly open EDA tab via data-turbo=false * Add configurable datasheet URL mode for KiCad API New setting "Datasheet field links to PDF" in KiCad EDA settings. When enabled (default), the datasheet field resolves to the actual PDF attachment URL. When disabled, it links to the Part-DB page (old behavior). Configurable via settings UI or EDA_KICAD_DATASHEET_AS_PDF env var. * Fix settings crash when upgrading: make datasheetAsPdf nullable The settings bundle stores values in the database. When upgrading from a version without datasheetAsPdf, the stored JSON lacks this key, causing a TypeError when assigning null to a non-nullable bool. Making it nullable with a fallback in KiCadHelper fixes the upgrade path. * Add functional tests for KiCad API v2 and batch EDA controller - KiCadApiV2ControllerTest: root, categories, parts, volatile fields, v1 vs v2 comparison, cache headers, 304 conditional request, auth - BatchEdaControllerTest: page load, empty redirect, form submission * Fix test failures: correct ids format and anonymous access assertion * Improve test coverage for BatchEdaController Add tests for: applying all EDA fields at once, custom redirect URL, and verifying unchecked fields are skipped. * Address PR review: rename to eda_visibility, merge migrations, API versioning Changes based on jbtronics' review of PR #1241: - Rename kicad_export -> eda_visibility (entities, forms, templates, translations, tests) with nullable bool for system default support - Merge two database migrations into one (Version20260211000000) - Rename createCachedJsonResponse -> createCacheableJsonResponse - Change bool $apiV2 -> int $apiVersion with version validation - EDA visibility field only shown for part parameters, not other entities - PopulateKicadCommand: check alternative names of footprints/categories - PopulateKicadCommand: support external JSON mapping file (--mapping-file) - Ship default mappings JSON at contrib/kicad-populate/default_mappings.json - Add system-wide defaultEdaVisibility setting in KiCadEDASettings - Add KiCad HTTP Library v2 spec link in controller docs * Fix duplicate loadMappingFile method causing PHP fatal error * Add tests for mapping file and alternative name matching, update populate command docs Add 5 new tests for PopulateKicadCommand covering: - Custom mapping file overriding defaults - Invalid JSON mapping file error handling - Missing mapping file error handling - Footprint alternative name matching - Category alternative name matching Update contrib README to document --mapping-file option, alternative name matching, and custom JSON mapping format. * Split out KiCad API v2 into separate PR as requested by maintainer Remove v2 controller, tests, and volatile field support from this PR. The v2 API will be submitted as a separate PR for focused discussion. * Improve test coverage for KiCadHelper and PopulateKicadCommand KiCadHelper: Add tests for orderdetail eda_visibility filtering, backward compatibility when no flags set, manufacturer/KiCost fields, and parameter with empty name skipping. PopulateKicadCommand: Add tests for mapping file with both footprints and categories sections, and mapping file with only categories. * Load populate Kicad default mappings from json file * Moved kicad:populate documentation to central docs * Added introduced column to PartTableColumns to make it configurable in the settings * Use TristateCheckboxes for parameter and orderdetail types * Fixed translation keys * Split up default eda visibility for parameters and purchase infos --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-01 22:10:13 +01:00
/**
* Finds the URL to the actual datasheet file for the given part.
* Searches attachments by type name, attachment name, and file extension.
* @return string|null The datasheet URL, or null if no datasheet was found.
*/
private function findDatasheetUrl(Part $part): ?string
{
$firstPdf = null;
foreach ($part->getAttachments() as $attachment) {
//Check if the attachment type name contains "datasheet"
$typeName = $attachment->getAttachmentType()?->getName() ?? '';
if (str_contains(mb_strtolower($typeName), 'datasheet')) {
return $this->getAttachmentUrl($attachment);
}
//Check if the attachment name contains "datasheet"
$name = mb_strtolower($attachment->getName());
if (str_contains($name, 'datasheet') || str_contains($name, 'data sheet')) {
return $this->getAttachmentUrl($attachment);
}
//Track first PDF as fallback (check internal extension or external URL path)
if ($firstPdf === null) {
$extension = $attachment->getExtension();
if ($extension === null && $attachment->hasExternal()) {
$urlPath = parse_url($attachment->getExternalPath(), PHP_URL_PATH);
$extension = is_string($urlPath) ? strtolower(pathinfo($urlPath, PATHINFO_EXTENSION)) : null;
}
if ($extension === 'pdf') {
$firstPdf = $attachment;
}
}
}
//Use first PDF attachment as fallback
if ($firstPdf !== null) {
return $this->getAttachmentUrl($firstPdf);
}
return null;
}
/**
* Returns an absolute URL for viewing the given attachment.
* Prefers the external URL (direct link) over the internal view route.
*/
private function getAttachmentUrl(Attachment $attachment): string
{
if ($attachment->hasExternal()) {
return $attachment->getExternalPath();
}
return $this->urlGenerator->generate(
'attachment_view',
['id' => $attachment->getId()],
UrlGeneratorInterface::ABSOLUTE_URL
);
}
}