- Add DocumentStorageService for file-based storage (replaces Base64 in DB) - Add DocumentServeController with /file and /download endpoints - Add DocumentUploadProcessor using FormData + filesystem storage - Add DocumentNormalizer exposing fileUrl/downloadUrl on all responses - Add DocumentFileCleanupListener for automatic file deletion - Add MigrateDocumentsToFilesystemCommand (Base64 → files, memory-safe) - Add ApiFilter (SearchFilter, ExistsFilter, OrderFilter) on Document entity - Add PdfCompressorService + refactor CompressPdfCommand for batch processing - Fix TypeMachine PUT: deserialize=false + validate=false to prevent UniqueEntity false positive and writableLink collection interference - Update CHANGELOG for v1.8.0 - Update frontend submodule Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
62 lines
1.8 KiB
PHP
62 lines
1.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Serializer;
|
|
|
|
use App\Entity\Document;
|
|
use ArrayObject;
|
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
|
|
|
use function is_array;
|
|
|
|
class DocumentNormalizer implements NormalizerInterface, NormalizerAwareInterface
|
|
{
|
|
use NormalizerAwareTrait;
|
|
|
|
private const ALREADY_CALLED = 'DOCUMENT_NORMALIZER_ALREADY_CALLED';
|
|
|
|
/**
|
|
* @return null|array<string, mixed>|ArrayObject<int|string, mixed>|bool|float|int|string
|
|
*/
|
|
public function normalize(mixed $data, ?string $format = null, array $context = []): array|ArrayObject|bool|float|int|string|null
|
|
{
|
|
$context[self::ALREADY_CALLED] = true;
|
|
|
|
/** @var null|array<string, mixed> $normalized */
|
|
$normalized = $this->normalizer->normalize($data, $format, $context);
|
|
|
|
if (is_array($normalized) && $data instanceof Document && $data->getId()) {
|
|
// Remove raw 'path' if present (never expose it to the client)
|
|
unset($normalized['path']);
|
|
|
|
// Always provide URL-based access
|
|
$normalized['fileUrl'] = '/api/documents/'.$data->getId().'/file';
|
|
$normalized['downloadUrl'] = '/api/documents/'.$data->getId().'/download';
|
|
}
|
|
|
|
return $normalized;
|
|
}
|
|
|
|
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
|
|
{
|
|
if (isset($context[self::ALREADY_CALLED])) {
|
|
return false;
|
|
}
|
|
|
|
return $data instanceof Document;
|
|
}
|
|
|
|
/**
|
|
* @return array<class-string, bool>
|
|
*/
|
|
public function getSupportedTypes(?string $format): array
|
|
{
|
|
return [
|
|
Document::class => false,
|
|
];
|
|
}
|
|
}
|