mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-20 17:15:51 +02:00
Correcty handle already existing elements in mass creation
This fixes issue #543
This commit is contained in:
parent
92a8107b9d
commit
ed4728fdb1
2 changed files with 59 additions and 22 deletions
|
@ -26,6 +26,7 @@ use App\Entity\Base\AbstractNamedDBElement;
|
|||
use App\Entity\Base\AbstractStructuralDBElement;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Repository\StructuralDBElementRepository;
|
||||
use App\Serializer\APIPlatform\SkippableItemNormalizer;
|
||||
use Symfony\Component\Validator\ConstraintViolationList;
|
||||
use function count;
|
||||
|
@ -50,12 +51,15 @@ class EntityImporter
|
|||
* Creates many entries at once, based on a (text) list of name.
|
||||
* The created entities are not persisted to database yet, so you have to do it yourself.
|
||||
*
|
||||
* @template T of AbstractNamedDBElement
|
||||
* @param string $lines The list of names seperated by \n
|
||||
* @param string $class_name The name of the class for which the entities should be created
|
||||
* @phpstan-param class-string<T> $class_name
|
||||
* @param AbstractStructuralDBElement|null $parent the element which will be used as parent element for new elements
|
||||
* @param array $errors an associative array containing all validation errors
|
||||
*
|
||||
* @return AbstractStructuralDBElement[] An array containing all valid imported entities (with the type $class_name)
|
||||
* @return AbstractNamedDBElement[] An array containing all valid imported entities (with the type $class_name)
|
||||
* @return T[]
|
||||
*/
|
||||
public function massCreation(string $lines, string $class_name, ?AbstractStructuralDBElement $parent = null, array &$errors = []): array
|
||||
{
|
||||
|
@ -69,6 +73,13 @@ class EntityImporter
|
|||
throw new InvalidArgumentException('$parent must have the same type as specified in $class_name!');
|
||||
}
|
||||
|
||||
//Ensure that parent is already persisted. Otherwise the getNewEntityFromPath function will not work.
|
||||
if ($parent !== null && $parent->getID() === null) {
|
||||
throw new InvalidArgumentException('The parent must persisted to database!');
|
||||
}
|
||||
|
||||
$repo = $this->em->getRepository($class_name);
|
||||
|
||||
$errors = [];
|
||||
$valid_entities = [];
|
||||
|
||||
|
@ -78,10 +89,10 @@ class EntityImporter
|
|||
$indentations = [0];
|
||||
|
||||
foreach ($names as $name) {
|
||||
//Count intendation level (whitespace characters at the beginning of the line)
|
||||
//Count indentation level (whitespace characters at the beginning of the line)
|
||||
$identSize = strlen($name)-strlen(ltrim($name));
|
||||
|
||||
//If the line is intendet more than the last line, we have a new parent element
|
||||
//If the line is intended more than the last line, we have a new parent element
|
||||
if ($identSize > end($indentations)) {
|
||||
$current_parent = $last_element;
|
||||
//Add the new indentation level to the stack
|
||||
|
@ -98,14 +109,25 @@ class EntityImporter
|
|||
//Skip empty lines (StrucuralDBElements must have a name)
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var AbstractStructuralDBElement $entity */
|
||||
//Create new element with given name
|
||||
$entity = new $class_name();
|
||||
$entity->setName($name);
|
||||
//Only set the parent if the entity is a StructuralDBElement
|
||||
if ($entity instanceof AbstractStructuralDBElement) {
|
||||
$entity->setParent($current_parent);
|
||||
//Create new element with given name. Using the function from the repository, to correctly reuse existing elements
|
||||
|
||||
if ($current_parent instanceof AbstractStructuralDBElement) {
|
||||
$new_path = $current_parent->getFullPath("->") . '->' . $name;
|
||||
} else {
|
||||
$new_path = $name;
|
||||
}
|
||||
//We can only use the getNewEntityFromPath function, if the repository is a StructuralDBElementRepository
|
||||
if ($repo instanceof StructuralDBElementRepository) {
|
||||
$entities = $repo->getNewEntityFromPath($new_path);
|
||||
$entity = end($entities);
|
||||
} else { //Otherwise just create a new entity
|
||||
$entity = new $class_name;
|
||||
$entity->setName($name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Validate entity
|
||||
$tmp = $this->validator->validate($entity);
|
||||
|
|
|
@ -24,10 +24,12 @@ namespace App\Tests\Services\ImportExportSystem;
|
|||
|
||||
use App\Entity\Attachments\AttachmentContainingDBElement;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\LabelSystem\LabelProfile;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\ImportExportSystem\EntityImporter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
|
||||
|
@ -68,10 +70,24 @@ class EntityImporterTest extends WebTestCase
|
|||
//Check parent
|
||||
$this->assertNull($results[0]->getMasterPictureAttachment());
|
||||
|
||||
$parent = new AttachmentType();
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$parent = $em->find(AttachmentType::class, 1);
|
||||
$results = $this->service->massCreation($lines, AttachmentType::class, $parent, $errors);
|
||||
$this->assertCount(3, $results);
|
||||
$this->assertSame($parent, $results[0]->getParent());
|
||||
|
||||
//Test for addition of existing elements
|
||||
$errors = [];
|
||||
$lines = "Node 3\n Node 3.new";
|
||||
$results = $this->service->massCreation($lines, AttachmentType::class, null, $errors);
|
||||
$this->assertCount(2, $results);
|
||||
$this->assertCount(0, $errors);
|
||||
$this->assertSame('Node 3', $results[0]->getName());
|
||||
//Node 3 must be an existing entity
|
||||
$this->assertNotNull($results[0]->getId());
|
||||
$this->assertSame('Node 3.new', $results[1]->getName());
|
||||
//Parent must be Node 3
|
||||
$this->assertSame($results[0], $results[1]->getParent());
|
||||
}
|
||||
|
||||
public function testNonStructuralClass(): void
|
||||
|
@ -81,13 +97,9 @@ Test1
|
|||
Test1.1
|
||||
Test2
|
||||
EOT;
|
||||
|
||||
//Define a new anonymous class, which is not structural. We can not use User here, because it does some validation
|
||||
$anonymous_object = new class extends AttachmentContainingDBElement {};
|
||||
$anonymous_class = get_class($anonymous_object);
|
||||
|
||||
$errors = [];
|
||||
$results = $this->service->massCreation($input, $anonymous_class, null, $errors);
|
||||
|
||||
$results = $this->service->massCreation($input, LabelProfile::class, null, $errors);
|
||||
|
||||
//Import must not fail, even with non-structural classes
|
||||
$this->assertCount(3, $results);
|
||||
|
@ -112,7 +124,8 @@ Test 2
|
|||
EOT;
|
||||
|
||||
$errors = [];
|
||||
$parent = new AttachmentType();
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$parent = $em->find(AttachmentType::class, 1);
|
||||
$results = $this->service->massCreation($input, AttachmentType::class, $parent, $errors);
|
||||
|
||||
//We have 7 elements, and 0 errors
|
||||
|
@ -148,13 +161,15 @@ EOT;
|
|||
public function testMassCreationErrors(): void
|
||||
{
|
||||
$errors = [];
|
||||
//Node 1 and Node 2 are created in datafixtures, so their attemp to create them again must fail.
|
||||
$lines = "Test 1\nNode 1\nNode 2";
|
||||
$longName = str_repeat('a', 256);
|
||||
|
||||
//The last node is too long, this must trigger a validation error
|
||||
$lines = "Test 1\nNode 1\n " . $longName;
|
||||
$results = $this->service->massCreation($lines, AttachmentType::class, null, $errors);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertCount(2, $results);
|
||||
$this->assertSame('Test 1', $results[0]->getName());
|
||||
$this->assertCount(2, $errors);
|
||||
$this->assertSame('Node 1', $errors[0]['entity']->getName());
|
||||
$this->assertCount(1, $errors);
|
||||
$this->assertSame($longName, $errors[0]['entity']->getName());
|
||||
}
|
||||
|
||||
public function formatDataProvider(): array
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue