extract pdf use case

This commit is contained in:
Yisroel Baum 2026-06-26 08:16:15 +03:00
parent b1bee8a16e
commit bc7937d2b3
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
7 changed files with 141 additions and 26 deletions

View file

@ -9,6 +9,8 @@ use App\Element\UseCases\DeleteChildElement\DeleteChildElement;
use App\Element\UseCases\DeleteChildElement\DeleteChildElementRequest; use App\Element\UseCases\DeleteChildElement\DeleteChildElementRequest;
use App\Element\UseCases\GetElement\GetElement; use App\Element\UseCases\GetElement\GetElement;
use App\Element\UseCases\GetElement\GetElementRequest; use App\Element\UseCases\GetElement\GetElementRequest;
use App\Element\UseCases\GetElementPdf\GetElementPdf;
use App\Element\UseCases\GetElementPdf\GetElementPdfRequest;
use App\Element\UseCases\ReorderChildElements\ReorderChildElements; use App\Element\UseCases\ReorderChildElements\ReorderChildElements;
use App\Element\UseCases\ReorderChildElements\ReorderChildElementsRequest; use App\Element\UseCases\ReorderChildElements\ReorderChildElementsRequest;
use App\Element\UseCases\UpdateElement\UpdateElement; use App\Element\UseCases\UpdateElement\UpdateElement;
@ -20,18 +22,16 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
class ElementController class ElementController
{ {
private const PDF_FOLDERS = ['short', 'long'];
public function __construct( public function __construct(
private GetElement $getElement, private GetElement $getElement,
private CreateChildElement $createChildElement, private CreateChildElement $createChildElement,
private DeleteChildElement $deleteChildElement, private DeleteChildElement $deleteChildElement,
private ReorderChildElements $reorderChildElements, private ReorderChildElements $reorderChildElements,
private UpdateElement $updateElement, private UpdateElement $updateElement,
private GetElementPdf $getElementPdf,
private FileUploader $fileUploader, private FileUploader $fileUploader,
) { ) {
} }
@ -72,31 +72,27 @@ class ElementController
string $folder, string $folder,
string $fileName, string $fileName,
): Response|JsonResponse { ): Response|JsonResponse {
if (!$this->isAllowedPdfFolder($folder)) { try {
$result = $this->getElementPdf->execute(
new GetElementPdfRequest(
folder: $folder,
fileName: $fileName,
)
);
} catch (NotFoundException $exception) {
return new JsonResponse([ return new JsonResponse([
'error' => 'PDF not found', 'error' => $exception->getMessage(),
], 404);
}
if (!preg_match('/^[A-Za-z0-9._-]+\.pdf$/', $fileName)) {
return new JsonResponse([
'error' => 'PDF not found',
], 404);
}
$path = "element-pdfs/$folder/$fileName";
if (!Storage::disk('public')->exists($path)) {
return new JsonResponse([
'error' => 'PDF not found',
], 404); ], 404);
} }
return new Response( return new Response(
Storage::disk('public')->get($path), $result->getContents(),
200, 200,
[ [
'Content-Type' => 'application/pdf', 'Content-Type' => $result->getMimeType(),
'Content-Disposition' => "inline; filename=\"$fileName\"", 'Content-Disposition' => 'inline; filename="'
. $result->getFileName()
. '"',
], ],
); );
} }
@ -409,9 +405,4 @@ class ElementController
return $path; return $path;
} }
private function isAllowedPdfFolder(string $folder): bool
{
return in_array($folder, self::PDF_FOLDERS, true);
}
} }

View file

@ -0,0 +1,53 @@
<?php
namespace App\Element\UseCases\GetElementPdf;
use App\Exceptions\NotFoundException;
use App\Shared\Files\StoredFileReader;
class GetElementPdf
{
private const PDF_FOLDERS = ['short', 'long'];
private const PDF_MIME_TYPE = 'application/pdf';
public function __construct(private StoredFileReader $storedFileReader)
{
}
/**
* @throws NotFoundException
*/
public function execute(GetElementPdfRequest $request): GetElementPdfResult
{
if (!$this->isAllowedPdfFolder($request->folder)) {
throw new NotFoundException('PDF not found');
}
if (!$this->isValidPdfFileName($request->fileName)) {
throw new NotFoundException('PDF not found');
}
$path = "element-pdfs/$request->folder/$request->fileName";
$contents = $this->storedFileReader->read($path);
if ($contents === null) {
throw new NotFoundException('PDF not found');
}
return new GetElementPdfResult(
contents: $contents,
fileName: $request->fileName,
mimeType: self::PDF_MIME_TYPE,
);
}
private function isAllowedPdfFolder(string $folder): bool
{
return in_array($folder, self::PDF_FOLDERS, true);
}
private function isValidPdfFileName(string $fileName): bool
{
return preg_match('/^[A-Za-z0-9._-]+\.pdf$/', $fileName) === 1;
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace App\Element\UseCases\GetElementPdf;
class GetElementPdfRequest
{
public function __construct(
public string $folder,
public string $fileName,
) {
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Element\UseCases\GetElementPdf;
class GetElementPdfResult
{
public function __construct(
private string $contents,
private string $fileName,
private string $mimeType,
) {
}
public function getContents(): string
{
return $this->contents;
}
public function getFileName(): string
{
return $this->fileName;
}
public function getMimeType(): string
{
return $this->mimeType;
}
}

View file

@ -10,6 +10,8 @@ use App\Auth\SystemClock;
use App\Auth\TokenGenerator; use App\Auth\TokenGenerator;
use App\Shared\Files\FileUploader; use App\Shared\Files\FileUploader;
use App\Shared\Files\LaravelFileUploader; use App\Shared\Files\LaravelFileUploader;
use App\Shared\Files\LaravelStoredFileReader;
use App\Shared\Files\StoredFileReader;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
@ -32,5 +34,9 @@ class AppServiceProvider extends ServiceProvider
FileUploader::class, FileUploader::class,
LaravelFileUploader::class, LaravelFileUploader::class,
); );
$this->app->bind(
StoredFileReader::class,
LaravelStoredFileReader::class,
);
} }
} }

View file

@ -0,0 +1,17 @@
<?php
namespace App\Shared\Files;
use Illuminate\Support\Facades\Storage;
class LaravelStoredFileReader implements StoredFileReader
{
public function read(string $path): ?string
{
if (!Storage::disk('public')->exists($path)) {
return null;
}
return Storage::disk('public')->get($path);
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Shared\Files;
interface StoredFileReader
{
public function read(string $path): ?string;
}