feat : add document upload processor, download controller and cleanup listener
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,11 +6,90 @@ namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use App\Entity\Task;
|
||||
use App\Entity\TaskDocument;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
class TaskDocumentProcessor implements ProcessorInterface
|
||||
/**
|
||||
* @implements ProcessorInterface<TaskDocument, TaskDocument>
|
||||
*/
|
||||
final readonly class TaskDocumentProcessor implements ProcessorInterface
|
||||
{
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
|
||||
private const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private Security $security,
|
||||
private RequestStack $requestStack,
|
||||
private string $uploadDir,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param TaskDocument $data
|
||||
*/
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): TaskDocument
|
||||
{
|
||||
return $data;
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
if (null === $request) {
|
||||
throw new BadRequestHttpException('No request available.');
|
||||
}
|
||||
|
||||
$file = $request->files->get('file');
|
||||
|
||||
if (null === $file || !$file->isValid()) {
|
||||
throw new BadRequestHttpException('No valid file uploaded.');
|
||||
}
|
||||
|
||||
if ($file->getSize() > self::MAX_FILE_SIZE) {
|
||||
throw new BadRequestHttpException('File size exceeds 50 MB limit.');
|
||||
}
|
||||
|
||||
$taskIri = $request->request->get('task');
|
||||
|
||||
if (null === $taskIri || '' === $taskIri) {
|
||||
throw new BadRequestHttpException('Task IRI is required.');
|
||||
}
|
||||
|
||||
// Extract task ID from IRI (e.g., "/api/tasks/42" -> 42)
|
||||
$taskId = (int) basename((string) $taskIri);
|
||||
$task = $this->entityManager->getRepository(Task::class)->find($taskId);
|
||||
|
||||
if (null === $task) {
|
||||
throw new BadRequestHttpException('Task not found.');
|
||||
}
|
||||
|
||||
// Capture file metadata BEFORE move() — move invalidates the temp file
|
||||
$originalName = $file->getClientOriginalName();
|
||||
$extension = $file->getClientOriginalExtension() ?: 'bin';
|
||||
$mimeType = $file->getClientMimeType() ?? 'application/octet-stream';
|
||||
$fileSize = $file->getSize();
|
||||
$uuid = Uuid::v4()->toRfc4122();
|
||||
$fileName = $uuid.'.'.$extension;
|
||||
|
||||
if (!is_dir($this->uploadDir)) {
|
||||
mkdir($this->uploadDir, 0o775, true);
|
||||
}
|
||||
|
||||
$file->move($this->uploadDir, $fileName);
|
||||
|
||||
$document = new TaskDocument();
|
||||
$document->setTask($task);
|
||||
$document->setOriginalName($originalName);
|
||||
$document->setFileName($fileName);
|
||||
$document->setMimeType($mimeType);
|
||||
$document->setSize($fileSize);
|
||||
$document->setCreatedAt(new DateTimeImmutable());
|
||||
$document->setUploadedBy($this->security->getUser());
|
||||
|
||||
$this->entityManager->persist($document);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user