diff --git a/src/Controller/KiCADAPIController.php b/src/Controller/KiCADAPIController.php index 46d05c47..2c67af5d 100644 --- a/src/Controller/KiCADAPIController.php +++ b/src/Controller/KiCADAPIController.php @@ -25,6 +25,7 @@ namespace App\Controller; use App\Entity\Parts\Category; use App\Entity\Parts\Part; +use App\Services\EDAIntegration\KiCADHelper; use App\Services\Trees\NodesListBuilder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -34,7 +35,11 @@ use Symfony\Component\Routing\Annotation\Route; #[Route('/kicad-api/v1')] class KiCADAPIController extends AbstractController { - public function __construct(private readonly EntityManagerInterface $em) + public function __construct( + private readonly EntityManagerInterface $em, + private readonly KiCADHelper $kiCADHelper, + + ) { } @@ -52,34 +57,18 @@ class KiCADAPIController extends AbstractController #[Route('/categories.json', name: 'kicad_api_categories')] public function categories(NodesListBuilder $nodesListBuilder): Response { - $categories = $nodesListBuilder->typeToNodesList(Category::class); - $result = []; - foreach ($categories as $category) { - $result[] = [ - 'id' => (string) $category->getId(), - 'name' => $category->getFullPath('/'), - ]; - } + $this->denyAccessUnlessGranted('@categories.read'); - return $this->json($result); + return $this->json($this->kiCADHelper->getCategories()); } #[Route('/parts/category/{category}.json', name: 'kicad_api_category')] public function categoryParts(Category $category): Response { - $category_repo = $this->em->getRepository(Category::class); - $parts = $category_repo->getParts($category); + $this->denyAccessUnlessGranted('read', $category); + $this->denyAccessUnlessGranted('@parts.read'); - $result = []; - foreach ($parts as $part) { - $result[] = [ - 'id' => (string) $part->getId(), - 'name' => $part->getName(), - 'description' => $part->getDescription(), - ]; - } - - return $this->json($result); + return $this->json($this->kiCADHelper->getCategoryParts($category)); } #[Route('/parts/{part}.json', name: 'kicad_api_part')] diff --git a/src/Services/EDAIntegration/KiCADHelper.php b/src/Services/EDAIntegration/KiCADHelper.php new file mode 100644 index 00000000..59cbc07c --- /dev/null +++ b/src/Services/EDAIntegration/KiCADHelper.php @@ -0,0 +1,101 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EDAIntegration; + +use App\Entity\Parts\Category; +use App\Services\Trees\NodesListBuilder; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Contracts\Cache\ItemInterface; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +class KiCADHelper +{ + + public function __construct( + private readonly NodesListBuilder $nodesListBuilder, + private readonly TagAwareCacheInterface $kicadCache, + private readonly EntityManagerInterface $em, + ) + { + + } + + /** + * 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', function (ItemInterface $item) { + //Invalidate the cache on category changes + $secure_class_name = str_replace('\\', '_', Category::class); + $item->tag($secure_class_name); + + $categories = $this->nodesListBuilder->typeToNodesList(Category::class); + $repo = $this->em->getRepository(Category::class); + $result = []; + foreach ($categories as $category) { + /** @var $category Category */ + //Ensure that the category contains parts + if ($repo->getPartsCount($category) < 1) { + continue; + } + + //Format the category for KiCAD + $result[] = [ + 'id' => (string) $category->getId(), + 'name' => $category->getFullPath('/'), + ]; + } + + 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 $category + * @return array + */ + public function getCategoryParts(Category $category): array + { + $category_repo = $this->em->getRepository(Category::class); + $parts = $category_repo->getParts($category); + + $result = []; + foreach ($parts as $part) { + $result[] = [ + 'id' => (string) $part->getId(), + 'name' => $part->getName(), + 'description' => $part->getDescription(), + ]; + } + + return $result; + } +} \ No newline at end of file