По умолчанию, путь до изображения хранится в виде названия файла. Чтобы превратить его в полный url - нужно вызывать хелпер. Но у нас ведь есть нормалайзеры! `class UploadableNormalizer implements NormalizerInterface { private array $classMetadataCache = [];

public function __construct( #[Autowire(service: 'serializer.normalizer.object')] private NormalizerInterface $normalizer, private UploaderHelper $uploaderHelper, private EntityManagerInterface $em, ) {}

public function normalize($object, ?string $format = null, array $context = []): array { // Сначала нормализуем как обычно, не забывая передать контекст // Там могут быть группы нормализации $data = $this->normalizer->normalize($object, $format, $context);

foreach ($this->extractUploadableFields($object) as $property => $propertyName) { if (empty($data[$propertyName])) { // Поле было удалено в результате нормализации continue; }

// Заменяем some.jpg на /uploads/fo/l/d/er/some.jpg $data[$propertyName] = $this->uploaderHelper->asset($object, $property); }

return $data; }

public function supportsNormalization($data, ?string $format = null, array $context = []): bool { if (!$this->em->contains($data)) { // Если сейчас сериализуется не доктриновский объект - не трогаем return false; }

$reflector = $this->em->getClassMetadata($data::class)->getReflectionClass();

// Сущность должна быть помечена, как бандловая $attrs = $reflector->getAttributes(Uploadable::class);

return !empty($attrs); }

public function getSupportedTypes(?string $format): array { // Данный нормализатор работает только с объектами // true ознаечает кешировать результат supports* return ['object' => true]; }

private function extractUploadableFields(object $object): array { // Забираем у доктрины рефлектор $reflector = $this->em->getClassMetadata($object::class)->getReflectionClass(); $className = $reflector->getName();

if (!isset($this->classMetadataCache[$className])) { // Пользуемся кешированием, чтобы для одного класса не парсить каждый раз $fields = [];

foreach ($reflector->getProperties() as $property) { // Перебираем свойства и забираем те, которыми управляет бандл $attrs = $property->getAttributes(UploadableField::class);

foreach ($attrs as $attr) { $uploadableField = $attr->newInstance(); $fields[$property->getName()] = $uploadableField->getFileNameProperty(); } }

$this->classMetadataCache[$className] = $fields; }

return $this->classMetadataCache[$className]; } } Из минусов - если кто-то напишет еще один нормалайзер на нашу сущность - они друг друга перетирать начнут. Но, я стараюсь прибегать к магии универсальных нормалайзеров как можно реже. Большую часть проблем можно разрулить на уровне групп нормализации и виртуальных геттерах.`