diff --git a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php index c2d35d92..97230319 100644 --- a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php +++ b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php @@ -22,6 +22,7 @@ declare(strict_types=1); */ namespace App\Form\Type\Helper; +use App\Entity\Base\AbstractStructuralDBElement; use App\Repository\StructuralDBElementRepository; use App\Services\Trees\NodesListBuilder; use Doctrine\ORM\EntityManagerInterface; @@ -32,13 +33,21 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader { private ?string $additional_element = null; + private ?AbstractStructuralDBElement $starting_element = null; + public function __construct(private readonly Options $options, private readonly NodesListBuilder $builder, private readonly EntityManagerInterface $entityManager) { } protected function loadChoices(): iterable { - $tmp = []; + //If the starting_element is set and not persisted yet, add it to the list + if ($this->starting_element !== null && $this->starting_element->getID() === null) { + $tmp = [$this->starting_element]; + } else { + $tmp = []; + } + if ($this->additional_element) { $tmp = $this->createNewEntitiesFromValue($this->additional_element); $this->additional_element = null; @@ -86,4 +95,23 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader return $this->additional_element; } + /** + * @return AbstractStructuralDBElement|null + */ + public function getStartingElement(): ?AbstractStructuralDBElement + { + return $this->starting_element; + } + + /** + * @param AbstractStructuralDBElement|null $starting_element + * @return StructuralEntityChoiceLoader + */ + public function setStartingElement(?AbstractStructuralDBElement $starting_element): StructuralEntityChoiceLoader + { + $this->starting_element = $starting_element; + return $this; + } + + } diff --git a/src/Form/Type/StructuralEntityType.php b/src/Form/Type/StructuralEntityType.php index 8afb6ce2..fbc294e4 100644 --- a/src/Form/Type/StructuralEntityType.php +++ b/src/Form/Type/StructuralEntityType.php @@ -122,6 +122,11 @@ class StructuralEntityType extends AbstractType public function modelTransform($value, array $options) { + $choice_loader = $options['choice_loader']; + if ($choice_loader instanceof StructuralEntityChoiceLoader) { + $choice_loader->setStartingElement($value); + } + return $value; } diff --git a/src/Repository/StructuralDBElementRepository.php b/src/Repository/StructuralDBElementRepository.php index c1882bda..48c10414 100644 --- a/src/Repository/StructuralDBElementRepository.php +++ b/src/Repository/StructuralDBElementRepository.php @@ -185,4 +185,69 @@ class StructuralDBElementRepository extends NamedDBElementRepository return $result; } + + /** + * Finds the element with the given name for the use with the InfoProvider System + * The name search is a bit more fuzzy than the normal findByName, because it is case-insensitive and ignores special characters. + * Also, it will try to find the element using the additional names field, of the elements. + * @param string $name + * @return AbstractStructuralDBElement|null + */ + public function findForInfoProvider(string $name): ?AbstractStructuralDBElement + { + //First try to find the element by name + $qb = $this->createQueryBuilder('e'); + //Use lowercase conversion to be case-insensitive + $qb->where($qb->expr()->like('LOWER(e.name)', 'LOWER(:name)')); + + $qb->setParameter('name', $name); + + $result = $qb->getQuery()->getResult(); + + if (count($result) === 1) { + return $result[0]; + } + + /*//If we have no result, try to find the element by additional names + $qb = $this->createQueryBuilder('e'); + //Use lowercase conversion to be case-insensitive + $qb->where($qb->expr()->like('LOWER(e.additional_names)', 'LOWER(:name)')); + $qb->setParameter('name', '%'.$name.'%'); + + $result = $qb->getQuery()->getResult(); + + if (count($result) === 1) { + return $result[0]; + }*/ + + //If we find nothing, return null + return null; + } + + /** + * Similar to findForInfoProvider, but will create a new element with the given name if none was found. + * @param string $name + * @return AbstractStructuralDBElement + */ + public function findOrCreateForInfoProvider(string $name): AbstractStructuralDBElement + { + $entity = $this->findForInfoProvider($name); + if (null === $entity) { + + //Try to find if we already have an element cached for this name + $entity = $this->getNewEntityFromCache($name, null); + if ($entity) { + return $entity; + } + + $class = $this->getClassName(); + /** @var AbstractStructuralDBElement $entity */ + $entity = new $class; + $entity->setName($name); + + $this->setNewEntityToCache($entity); + } + + return $entity; + } } diff --git a/src/Services/InfoProviderSystem/DTOtoEntityConverter.php b/src/Services/InfoProviderSystem/DTOtoEntityConverter.php index 749467e5..b11382d2 100644 --- a/src/Services/InfoProviderSystem/DTOtoEntityConverter.php +++ b/src/Services/InfoProviderSystem/DTOtoEntityConverter.php @@ -25,13 +25,16 @@ namespace App\Services\InfoProviderSystem; use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\PartAttachment; +use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Parameters\AbstractParameter; use App\Entity\Parameters\PartParameter; +use App\Entity\Parts\Manufacturer; use App\Entity\Parts\ManufacturingStatus; use App\Entity\Parts\Part; use App\Services\InfoProviderSystem\DTOs\FileDTO; use App\Services\InfoProviderSystem\DTOs\ParameterDTO; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use Doctrine\ORM\EntityManagerInterface; /** * This class converts DTOs to entities which can be persisted in the DB @@ -39,6 +42,10 @@ use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; class DTOtoEntityConverter { + public function __construct(private readonly EntityManagerInterface $em) + { + } + public function convertParameter(ParameterDTO $dto, PartParameter $entity = new PartParameter()): PartParameter { $entity->setName($dto->name); @@ -79,6 +86,8 @@ class DTOtoEntityConverter $entity->setDescription($dto->description ?? ''); $entity->setComment($dto->notes ?? ''); + $entity->setManufacturer($this->getOrCreateEntity(Manufacturer::class, $dto->manufacturer)); + $entity->setManufacturerProductNumber($dto->mpn ?? ''); $entity->setManufacturingStatus($dto->manufacturing_status ?? ManufacturingStatus::NOT_SET); @@ -95,4 +104,14 @@ class DTOtoEntityConverter return $entity; } + private function getOrCreateEntity(string $class, ?string $name): ?AbstractStructuralDBElement + { + //Fall through to make converting easier + if ($name === null) { + return null; + } + + return $this->em->getRepository($class)->findOrCreateForInfoProvider($name); + } + } \ No newline at end of file