<?php
namespace App\Service;
use App\Entity\DeliveryMan;
use App\Entity\Document;
use App\Entity\Rib;
use App\Entity\TypeDocument;
use App\Entity\Variables\DelivererDocumentStatus;
use App\Enum\TypeDocumentEnum;
use App\Repository\DocumentRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\String\Slugger\SluggerInterface;
class FileUploader
{
public function __construct(
private string $targetDirectory,
private SluggerInterface $slugger,
private ManagerRegistry $doctrine,
private DocumentRepository $documentRepository,
private EntityManagerInterface $entityManager,
private Filesystem $fileSystem,
) {
}
/**
* @return string
*/
public function getOriginalFileName(UploadedFile $file)
{
return pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
}
public function getUniqueFileName(UploadedFile $file): string
{
$originalFilename = $this->getOriginalFileName($file);
$safeFilename = $this->slugger->slug($originalFilename);
return $safeFilename.'-'.uniqid().'.'.$file->guessExtension();
}
public function upload(UploadedFile $file, string $fileName = null): string
{
if (!$fileName) {
$fileName = $this->getUniqueFileName($file);
}
try {
$file->move($this->getTargetDirectory(), $fileName);
} catch (FileException $e) {
// ... handle exception if something happens during file upload
throw new \Exception('File upload error : '.$e->getMessage());
}
return $fileName;
}
/**
* update and upload Document.
*
* @throws \Exception
*/
public function updateDocument(Document $document, UploadedFile $file, string $documentType = ''): Document
{
if ('' == $documentType) {
$documentType = TypeDocumentEnum::getLabel(TypeDocumentEnum::PDF);
}
$originalFileName = $this->getOriginalFileName($file);
$uniqueFileName = $this->getUniqueFileName($file);
$documentFileName = $this->upload($file, $uniqueFileName);
$document->setDisplayName($originalFileName);
$document->setRealName($documentFileName);
$type = $this->doctrine->getRepository(TypeDocument::class)->findOneBy(['name' => $documentType]);
if (!$type) {
throw new \Exception('Type not found', Response::HTTP_NOT_FOUND);
}
$document->setType($type);
return $document;
}
public function getTargetDirectory(): string
{
return $this->targetDirectory;
}
public function getTempFile(string $fileName, Spreadsheet $spreadsheet): string
{
// Create Office 2007 Excel (XLSX Format)
$writer = new Xlsx($spreadsheet);
$temp_file = tempnam(sys_get_temp_dir(), $fileName);
if (!$temp_file) {
throw new \Exception('Temp file undefined', Response::HTTP_NOT_FOUND);
}
// Create the excel file in the tmp directory of the system
$writer->save($temp_file);
return $temp_file;
}
public function uploadFile(TypeDocumentEnum $docType, FormInterface $formDocuments, DeliveryMan $deliveryMan, ?string $directory): void
{
$idFile = $formDocuments->get($docType->formName())->getData();
$document = $this->documentRepository->findOneBy(['deliveryMan' => $deliveryMan, 'type' => $docType->value]);
if ($idFile && $formDocuments[$docType->formName()]) {
$uploadedFile = $formDocuments[$docType->formName()]->getData() instanceof UploadedFile
? $formDocuments[$docType->formName()]->getData()
: ($formDocuments[$docType->formName()]->get('realName') ? $formDocuments[$docType->formName()]->get('realName')->getData() : null);
if (!$uploadedFile) {
throw new \Exception('File not found in Form', Response::HTTP_INTERNAL_SERVER_ERROR);
}
$documentUploader = new DocumentUploader($directory ?? '', $uploadedFile);
$documentUploader->setTargetDirectory($directory ?? '');
$documentUploader->upload();
$fileName = $documentUploader->getFileName();
if ($document) {
$unlink = unlink($directory.'/'.$document->getRealName());
if (!$unlink) {
throw new \Exception('Cannot be unlink', Response::HTTP_FORBIDDEN);
}
$document->setRealName($fileName);
} else {
$document = new Document();
$document->setRealName($fileName);
$document->setDeliveryMan($deliveryMan);
$document->setDisplayName($docType->label());
$type = $this->doctrine->getRepository(TypeDocument::class)->findOneBy(['name' => $docType->label()]);
if (!$type) {
throw new \Exception('Type not found', Response::HTTP_NOT_FOUND);
}
$document->setType($type);
$documentStatus = $this->doctrine->getRepository(DelivererDocumentStatus::class)->findOneBy(['status' => 'En attente']);
if (!$documentStatus) {
throw new \Exception('DocumentStatus not found', Response::HTTP_NOT_FOUND);
}
$document->setDocumentStatus($documentStatus);
}
$this->entityManager->persist($document);
$this->entityManager->flush();
} elseif ($formDocuments->has('suppr'.$docType->formName()) && '' != $formDocuments->get('suppr'.$docType->formName())->getData() && $document) {
$this->deleteFile($directory, $document);
}
}
private function deleteFile(?string $directory, ?Document $document): void
{
if (!$document) {
return;
}
$filePath = $directory.'/'.$document->getRealName();
if ($this->fileSystem->exists($filePath)) {
$this->fileSystem->remove($filePath);
}
$this->entityManager->remove($document);
$this->entityManager->flush();
}
/**
* @todo A refacto
*/
/**public function uploadFile(
string $doc,
FormInterface $formDocuments,
DeliveryMan $deliveryMan,
?string $directory
): void {
/** @var ?string $idFile
$idFile = $formDocuments->get($doc)->getData();
// get previous file if exists
$document = $this->documentRepository->findOneBy(['deliveryMan' => $deliveryMan, 'displayName' => $doc]);
// if new file
if ($idFile && $formDocuments[$doc]) {
$documentUploader = new DocumentUploader($directory ?? '', $formDocuments[$doc]);
// upload file
$documentUploader->upload();
// get file name
$fileName = $documentUploader->getFileName();
// if we have to delete previous file
if (isset($document) && $fileName != $document->getRealName()) {
// unlink old file
$unlink = unlink($directory . '/' . $document->getRealName());
if (!$unlink) {
throw new \Exception('Cannot be unlink', Response::HTTP_FORBIDDEN);
}
// set new file name
$document->setRealName($fileName);
}
// if no previous file
else {
// create new document
$document = new Document();
$document->setRealName($fileName);
$document->setDeliveryMan($deliveryMan);
$document->setDisplayName($doc);
$type = $this->doctrine->getRepository(TypeDocument::class)->findOneBy(['name' => $doc]);
if (!$type) {
throw new \Exception('Type not found', Response::HTTP_NOT_FOUND);
}
$documentStatus = $this->doctrine->getRepository(DelivererDocumentStatus::class)->findOneBy(['status' => 'En attente']);
if (!$documentStatus) {
throw new \Exception('DocumentStatus not found', Response::HTTP_NOT_FOUND);
}
$document->setDocumentStatus($documentStatus);
}
// add to DB
$this->entityManager->persist($document);
$this->entityManager->flush();
}
// else if we want to drop the old file
elseif ('' != $formDocuments->get('suppr' . $doc)->getData()) {
// unlink old file
$unlink = unlink($directory ?? '/' . $document->getRealName());
if (!$unlink) {
throw new \Exception('Cannot be unlink', Response::HTTP_FORBIDDEN);
}
$document->setDeliveryMan(null);
$this->entityManager->remove($document);
$this->entityManager->flush();
}
}*/
/**
* @todo A refacto
*/
public function uploadRib(?UserInterface $user, Request $request, FormInterface $form, string $directory, ?Rib $rib): bool
{
$session = $request->getSession();
$ribStatus = $this->doctrine->getRepository(DelivererDocumentStatus::class)->findOneBy(['status' => 'En attente']);
if (!$ribStatus) {
throw new \Exception('RibStatus not found', Response::HTTP_NOT_FOUND);
}
if (!$rib && $user) {
$rib = new Rib();
$rib->setUser($user);
$rib->setRibStatus($ribStatus);
} elseif ($rib && $rib->getDocument()) {
$session->set('rib_document', $rib->getDocument());
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (!$rib) {
throw new \Exception('Rib not found', Response::HTTP_NOT_FOUND);
}
/** @var string $rib_document */
$rib_document = $session->get('rib_document');
if ('' != $rib->getDocument()) {
$documentUploader = new DocumentUploader($directory, $form->get('document'));
$documentUploader->upload();
$rib->setDocument($documentUploader->getFileName());
// suppression de l'ancier fichier sur le serveur si il y en avait un
if ('' != $rib_document) {
unlink($directory.'/'.$rib_document);
}
}
// si on veut garder l'ancien fichier
elseif ('' == $form->get('supprRIB')->getData()) {
$rib->setDocument($rib_document);
}
// si on veut supprimer l'ancien fichier
elseif ('' != $rib_document) {
unlink($directory.'/'.$rib_document);
$rib->setRibStatus($ribStatus);
}
$session->remove('rib_document');
$this->entityManager->persist($rib);
$this->entityManager->flush();
return true;
}
return false;
}
public function delete(string $directory, string $fileName): void
{
$filePath = $directory.'/'.$fileName;
if (file_exists($filePath) && !unlink($filePath)) {
throw new \Exception('Cannot unlink file', Response::HTTP_FORBIDDEN);
}
}
}