mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-22 09:53:35 +02:00
Allow to automatically find or create entities from database based on info providers
This commit is contained in:
parent
f9bce3dfdb
commit
6cd9640b30
4 changed files with 118 additions and 1 deletions
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||||
*/
|
*/
|
||||||
namespace App\Form\Type\Helper;
|
namespace App\Form\Type\Helper;
|
||||||
|
|
||||||
|
use App\Entity\Base\AbstractStructuralDBElement;
|
||||||
use App\Repository\StructuralDBElementRepository;
|
use App\Repository\StructuralDBElementRepository;
|
||||||
use App\Services\Trees\NodesListBuilder;
|
use App\Services\Trees\NodesListBuilder;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
@ -32,13 +33,21 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader
|
||||||
{
|
{
|
||||||
private ?string $additional_element = null;
|
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)
|
public function __construct(private readonly Options $options, private readonly NodesListBuilder $builder, private readonly EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadChoices(): iterable
|
protected function loadChoices(): iterable
|
||||||
{
|
{
|
||||||
|
//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 = [];
|
$tmp = [];
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->additional_element) {
|
if ($this->additional_element) {
|
||||||
$tmp = $this->createNewEntitiesFromValue($this->additional_element);
|
$tmp = $this->createNewEntitiesFromValue($this->additional_element);
|
||||||
$this->additional_element = null;
|
$this->additional_element = null;
|
||||||
|
@ -86,4 +95,23 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader
|
||||||
return $this->additional_element;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,11 @@ class StructuralEntityType extends AbstractType
|
||||||
|
|
||||||
public function modelTransform($value, array $options)
|
public function modelTransform($value, array $options)
|
||||||
{
|
{
|
||||||
|
$choice_loader = $options['choice_loader'];
|
||||||
|
if ($choice_loader instanceof StructuralEntityChoiceLoader) {
|
||||||
|
$choice_loader->setStartingElement($value);
|
||||||
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,4 +185,69 @@ class StructuralDBElementRepository extends NamedDBElementRepository
|
||||||
|
|
||||||
return $result;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,16 @@ namespace App\Services\InfoProviderSystem;
|
||||||
|
|
||||||
use App\Entity\Attachments\AttachmentType;
|
use App\Entity\Attachments\AttachmentType;
|
||||||
use App\Entity\Attachments\PartAttachment;
|
use App\Entity\Attachments\PartAttachment;
|
||||||
|
use App\Entity\Base\AbstractStructuralDBElement;
|
||||||
use App\Entity\Parameters\AbstractParameter;
|
use App\Entity\Parameters\AbstractParameter;
|
||||||
use App\Entity\Parameters\PartParameter;
|
use App\Entity\Parameters\PartParameter;
|
||||||
|
use App\Entity\Parts\Manufacturer;
|
||||||
use App\Entity\Parts\ManufacturingStatus;
|
use App\Entity\Parts\ManufacturingStatus;
|
||||||
use App\Entity\Parts\Part;
|
use App\Entity\Parts\Part;
|
||||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class converts DTOs to entities which can be persisted in the DB
|
* 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
|
class DTOtoEntityConverter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function __construct(private readonly EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public function convertParameter(ParameterDTO $dto, PartParameter $entity = new PartParameter()): PartParameter
|
public function convertParameter(ParameterDTO $dto, PartParameter $entity = new PartParameter()): PartParameter
|
||||||
{
|
{
|
||||||
$entity->setName($dto->name);
|
$entity->setName($dto->name);
|
||||||
|
@ -79,6 +86,8 @@ class DTOtoEntityConverter
|
||||||
$entity->setDescription($dto->description ?? '');
|
$entity->setDescription($dto->description ?? '');
|
||||||
$entity->setComment($dto->notes ?? '');
|
$entity->setComment($dto->notes ?? '');
|
||||||
|
|
||||||
|
$entity->setManufacturer($this->getOrCreateEntity(Manufacturer::class, $dto->manufacturer));
|
||||||
|
|
||||||
$entity->setManufacturerProductNumber($dto->mpn ?? '');
|
$entity->setManufacturerProductNumber($dto->mpn ?? '');
|
||||||
$entity->setManufacturingStatus($dto->manufacturing_status ?? ManufacturingStatus::NOT_SET);
|
$entity->setManufacturingStatus($dto->manufacturing_status ?? ManufacturingStatus::NOT_SET);
|
||||||
|
|
||||||
|
@ -95,4 +104,14 @@ class DTOtoEntityConverter
|
||||||
return $entity;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue