diff --git a/src/Command/Migrations/ImportPartKeeprCommand.php b/src/Command/Migrations/ImportPartKeeprCommand.php index d860ce03..829dfbd0 100644 --- a/src/Command/Migrations/ImportPartKeeprCommand.php +++ b/src/Command/Migrations/ImportPartKeeprCommand.php @@ -91,6 +91,14 @@ class ImportPartKeeprCommand extends Command $io->info('Importing manufacturers...'); $count = $this->importer->importManufacturers($data); $io->success('Imported '.$count.' manufacturers.'); + + $io->info('Importing categories...'); + $count = $this->importer->importCategories($data); + $io->success('Imported '.$count.' categories.'); + + $io->info('Importing Footprints...'); + $count = $this->importer->importFootprints($data); + $io->success('Imported '.$count.' footprints.'); } } \ No newline at end of file diff --git a/src/Services/ImportExportSystem/PartkeeprImporter.php b/src/Services/ImportExportSystem/PartkeeprImporter.php index d2bf13f7..5887b56c 100644 --- a/src/Services/ImportExportSystem/PartkeeprImporter.php +++ b/src/Services/ImportExportSystem/PartkeeprImporter.php @@ -23,6 +23,9 @@ namespace App\Services\ImportExportSystem; use App\Doctrine\Purger\ResetAutoIncrementORMPurger; use App\Doctrine\Purger\ResetAutoIncrementPurgerFactory; use App\Entity\Base\AbstractDBElement; +use App\Entity\Base\AbstractStructuralDBElement; +use App\Entity\Parts\Category; +use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; @@ -144,8 +147,141 @@ class PartkeeprImporter return count($partunit_data); } - public function setIDOfEntity(AbstractDBElement $element, int $id): void + public function importCategories(array $data): int { + if (!isset($data['partcategory'])) { + throw new \RuntimeException('$data must contain a "partcategory" key!'); + } + + $partcategory_data = $data['partcategory']; + + //In a first step, create all categories like they were a flat structure (so ignore the parent) + foreach ($partcategory_data as $partcategory) { + $category = new Category(); + $category->setName($partcategory['name']); + $category->setComment($partcategory['description']); + + $this->setIDOfEntity($category, $partcategory['id']); + $this->em->persist($category); + } + + $this->em->flush(); + + //In a second step, set the correct parent element + foreach ($partcategory_data as $partcategory) { + $this->setParent(Category::class, $partcategory['id'], $partcategory['parent_id']); + } + $this->em->flush(); + + return count($partcategory_data); + } + + private function importElementsWithCategory(array $data, string $target_class, string $data_prefix): int + { + + } + + public function importFootprints(array $data): int + { + if (!isset($data['footprint'])) { + throw new \RuntimeException('$data must contain a "footprint" key!'); + } + if (!isset($data['footprintcategory'])) { + throw new \RuntimeException('$data must contain a "footprintcategory" key!'); + } + + //We import the footprints first, as we need the IDs of the footprints be our real DBs later (as we match the part import by ID) + //As the footprints category is not existing yet, we just skip the parent field for now + $footprint_data = $data['footprint']; + $max_footprint_id = 0; + foreach ($footprint_data as $footprint) { + $entity = new Footprint(); + $entity->setName($footprint['name']); + $entity->setComment($footprint['description']); + + $this->setIDOfEntity($entity, $footprint['id']); + $this->em->persist($entity); + $max_footprint_id = max($max_footprint_id, (int) $footprint['id']); + } + + //Import the footprint categories ignoring the parents for now + //Their IDs are $max_footprint_id + $ID + $footprintcategory_data = $data['footprintcategory']; + foreach ($footprintcategory_data as $footprintcategory) { + $entity = new Footprint(); + $entity->setName($footprintcategory['name']); + $entity->setComment($footprintcategory['description']); + //Categories are not assignable to parts, so we set them to not selectable + $entity->setNotSelectable(true); + + $this->setIDOfEntity($entity, $max_footprint_id + (int) $footprintcategory['id']); + $this->em->persist($entity); + } + + $this->em->flush(); + + //Now we can correct the parents and category IDs of the parts + foreach ($footprintcategory_data as $footprintcategory) { + //We have to use the mapped IDs here, as the imported ID is not the effective ID + if ($footprintcategory['parent_id']) { + $this->setParent(Footprint::class, $max_footprint_id + (int)$footprintcategory['id'], + $max_footprint_id + (int)$footprintcategory['parent_id']); + } + } + foreach ($footprint_data as $footprint) { + if ($footprint['category_id']) { + $this->setParent(Footprint::class, $footprint['id'], + $max_footprint_id + (int)$footprint['category_id']); + } + } + + $this->em->flush(); + + return count($footprint_data) + count($footprintcategory_data); + } + + /** + * Assigns the parent to the given entity, using the numerical IDs from the imported data. + * @param string $class + * @param int|string $element_id + * @param int|string $parent_id + * @return AbstractStructuralDBElement The structural element that was modified (with $element_id) + */ + private function setParent(string $class, $element_id, $parent_id): AbstractStructuralDBElement + { + $element = $this->em->find($class, (int) $element_id); + if (!$element) { + throw new \RuntimeException(sprintf('Could not find element with ID %s', $element_id)); + } + + //If the parent is null, we're done + if (!$parent_id) { + return $element; + } + + $parent = $this->em->find($class, (int) $parent_id); + if (!$parent) { + throw new \RuntimeException(sprintf('Could not find parent with ID %s', $parent_id)); + } + + $element->setParent($parent); + return $element; + } + + /** + * Set the ID of an entity to a specific value. Must be called before persisting the entity, but before flushing. + * @param AbstractDBElement $element + * @param int|string $id + * @return void + */ + public function setIDOfEntity(AbstractDBElement $element, $id): void + { + if (!is_int($id) && !is_string($id)) { + throw new \InvalidArgumentException('ID must be an integer or string'); + } + + $id = (int) $id; + $metadata = $this->em->getClassMetadata(get_class($element)); $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); $metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());