Allow to import PartKeepr attachments

This commit is contained in:
Jan Böhmer 2023-03-25 22:59:31 +01:00
parent ae438f1650
commit bcaf8e9912
4 changed files with 136 additions and 2 deletions

View file

@ -21,6 +21,9 @@
namespace App\Services\ImportExportSystem\PartKeeprImporter;
use App\Doctrine\Purger\ResetAutoIncrementORMPurger;
use App\Entity\Attachments\FootprintAttachment;
use App\Entity\Attachments\ManufacturerAttachment;
use App\Entity\Attachments\StorelocationAttachment;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Contracts\TimeStampableInterface;
@ -125,6 +128,8 @@ class PKDatastructureImporter
$this->em->flush();
$this->importAttachments($data, 'manufacturericlogo', Manufacturer::class, 'manufacturer_id', ManufacturerAttachment::class);
return count($manufacturer_data);
}
@ -249,11 +254,22 @@ class PKDatastructureImporter
public function importFootprints(array $data): int
{
return $this->importElementsWithCategory($data, Footprint::class, 'footprint');
$count = $this->importElementsWithCategory($data, Footprint::class, 'footprint');
//Footprints have both attachments and images
$this->importAttachments($data, 'footprintattachment', Footprint::class, 'footprint_id', FootprintAttachment::class);
$this->importAttachments($data, 'footprintimage', Footprint::class, 'footprint_id', FootprintAttachment::class);
return $count;
}
public function importStorelocations(array $data): int
{
return $this->importElementsWithCategory($data, Storelocation::class, 'storagelocation');
$count = $this->importElementsWithCategory($data, Storelocation::class, 'storagelocation');
//Footprints have both attachments and images
$this->importAttachments($data, 'storagelocationimage', Storelocation::class, 'footprint_id', StorelocationAttachment::class);
return $count;
}
}

View file

@ -20,6 +20,9 @@
namespace App\Services\ImportExportSystem\PartKeeprImporter;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Contracts\TimeStampableInterface;
@ -35,6 +38,114 @@ trait PKImportHelperTrait
protected EntityManagerInterface $em;
protected PropertyAccessorInterface $propertyAccessor;
private ?AttachmentType $import_attachment_type = null;
/**
* Converts a PartKeepr attachment/image row to an Attachment entity.
* @param array $attachment_row The attachment row from the PartKeepr database
* @param string $target_class The target class for the attachment
* @param string $type The type of the attachment (attachment or image)
* @return Attachment
* @throws \Exception
*/
protected function convertAttachmentDataToEntity(array $attachment_row, string $target_class, string $type): Attachment
{
//By default we use the cached version
if (!$this->import_attachment_type) {
//Get the import attachment type
$this->import_attachment_type = $this->em->getRepository(AttachmentType::class)->findOneBy([
'name' => 'PartKeepr Attachment'
]);
if (!$this->import_attachment_type) { //If not existing in DB create it
$this->import_attachment_type = new AttachmentType();
$this->import_attachment_type->setName('PartKeepr Attachment');
$this->em->persist($this->import_attachment_type);
}
}
if (!in_array($type, ['attachment', 'image'], true)) {
throw new \InvalidArgumentException(sprintf('The type %s is not a valid attachment type', $type));
}
if (!is_a($target_class, Attachment::class, true)) {
throw new \InvalidArgumentException(sprintf('The target class %s is not a subclass of %s', $target_class, Attachment::class));
}
/** @var Attachment $attachment */
$attachment = new $target_class();
if (!empty($attachment_row['description'])) {
$attachment->setName($attachment_row['description']);
} else {
$attachment->setName($attachment_row['originalname']);
}
$attachment->setFilename($attachment_row['originalname']);
$attachment->setAttachmentType($this->import_attachment_type);
$this->setCreationDate($attachment, $attachment_row['created']);
//Determine file extension (if the extension is empty, we use the original extension)
if (empty($attachment_row['extension'])) {
$attachment_row['extension'] = pathinfo($attachment_row['originalname'], PATHINFO_EXTENSION);
}
//Determine file path
//Images are stored in the (public) media folder, attachments in the (private) uploads/ folder
$path = $type === 'attachment' ? '%SECURE%' : '%MEDIA%';
//The folder is the type of the attachment from the PartKeepr database
$path .= '/'.$attachment_row['type'];
//Next comes the filename plus extension
$path .= '/'.$attachment_row['filename'].'.'.$attachment_row['extension'];
$attachment->setPath($path);
return $attachment;
}
/**
* Imports the attachments from the given data
* @param array $data The PartKeepr database
* @param string $table_name The table name for the attachments (if it contain "image", it will be treated as an image)
* @param string $target_class The target class (e.g. Part)
* @param string $target_id_field The field name where the target ID is stored
* @param string $attachment_class The attachment class (e.g. PartAttachment)
* @return void
*/
protected function importAttachments(array $data, string $table_name, string $target_class, string $target_id_field, string $attachment_class): void
{
//Determine if we have an image or an attachment
$type = str_contains($table_name, 'image') || str_contains($table_name, 'iclogo') ? 'image' : 'attachment';
if (!isset($data[$table_name])) {
throw new \RuntimeException(sprintf('The table %s does not exist in the PartKeepr database', $table_name));
}
if (!is_a($target_class, AttachmentContainingDBElement::class, true)) {
throw new \InvalidArgumentException(sprintf('The target class %s is not a subclass of %s', $target_class, AttachmentContainingDBElement::class));
}
if (!is_a($attachment_class, Attachment::class, true)) {
throw new \InvalidArgumentException(sprintf('The attachment class %s is not a subclass of %s', $attachment_class, Attachment::class));
}
//Get the table data
$table_data = $data[$table_name];
foreach($table_data as $attachment_row) {
$attachment = $this->convertAttachmentDataToEntity($attachment_row, $attachment_class, $type);
//Retrieve the target entity
$target_id = (int) $attachment_row[$target_id_field];
/** @var AttachmentContainingDBElement $target */
$target = $this->em->find($target_class, $target_id);
if (!$target) {
throw new \RuntimeException(sprintf('Could not find target entity with ID %s', $target_id));
}
$target->addAttachment($attachment);
$this->em->persist($attachment);
}
$this->em->flush();
}
/**
* Assigns the parent to the given entity, using the numerical IDs from the imported data.
* @param string $class

View file

@ -20,6 +20,7 @@
namespace App\Services\ImportExportSystem\PartKeeprImporter;
use App\Entity\Attachments\ProjectAttachment;
use App\Entity\Parts\Part;
use App\Entity\ProjectSystem\Project;
use App\Entity\ProjectSystem\ProjectBOMEntry;
@ -96,6 +97,8 @@ class PKOptionalImporter
}
$this->em->flush();
$this->importAttachments($data, 'projectattachment', Project::class, 'project_id', ProjectAttachment::class);
return count($projects_data);
}

View file

@ -20,6 +20,7 @@
namespace App\Services\ImportExportSystem\PartKeeprImporter;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Parameters\PartParameter;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
@ -119,6 +120,9 @@ class PKPartImporter
$this->importPartParameters($data);
$this->importOrderdetails($data);
//Import attachments
$this->importAttachments($data, 'partattachment', Part::class, 'part_id', PartAttachment::class);
return count($part_data);
}