routeParameters->getString('ulid'); // Find image by ULID $image = $this->imageRepository->findByUlid($ulid); if (! $image) { throw NotFound::create( ErrorCode::ENTITY_NOT_FOUND, "Image with ULID {$ulid} not found" )->withData(['ulid' => $ulid]); } // Parse request body $updateData = $this->parseUpdateData($request); // Update only allowed fields $updatedImage = $image; if (isset($updateData['alt_text'])) { $updatedImage = $updatedImage->withAltText($updateData['alt_text']); } if (isset($updateData['filename'])) { $this->validateFilename($updateData['filename']); $updatedImage = $updatedImage->withFilename($updateData['filename']); } // Save updated image $this->imageRepository->save($updatedImage); // Return updated image data return new JsonResponse([ 'ulid' => $updatedImage->getUlidString(), 'filename' => $updatedImage->filename, 'original_filename' => $updatedImage->originalFilename, 'url' => '/media/images/' . $updatedImage->path->toString(), 'thumbnail_url' => '/media/images/thumbnails/' . $updatedImage->path->toString(), 'alt_text' => $updatedImage->altText, 'dimensions' => [ 'width' => $updatedImage->width, 'height' => $updatedImage->height, 'aspect_ratio' => $updatedImage->getAspectRatio(), 'orientation' => $updatedImage->getDimensions()->getOrientation()->value, ], 'mime_type' => $updatedImage->mimeType->value, 'file_size' => [ 'bytes' => $updatedImage->fileSize->toBytes(), 'human_readable' => $updatedImage->getHumanReadableFileSize(), ], 'hash' => $updatedImage->hash->toString(), 'is_image' => $updatedImage->isImageFile(), 'created_at' => $updatedImage->ulid->getDateTime()->format('c'), 'variants' => array_map(fn ($variant) => [ 'type' => $variant->variantType, 'width' => $variant->width, 'height' => $variant->height, 'path' => $variant->path, 'url' => '/media/images/' . $variant->path, ], $updatedImage->variants ?? []), ], Status::OK); } /** * Parse update data from request body */ private function parseUpdateData(HttpRequest $request): array { $body = $request->parsedBody->toArray(); // Only allow specific fields to be updated $allowedFields = ['alt_text', 'filename']; $updateData = []; foreach ($allowedFields as $field) { if (array_key_exists($field, $body)) { $updateData[$field] = $body[$field]; } } return $updateData; } /** * Validate filename */ private function validateFilename(string $filename): void { if (empty(trim($filename))) { throw FrameworkException::create( ErrorCode::VAL_INVALID_FORMAT, 'Filename cannot be empty' )->withData(['field' => 'filename']); } // Check for invalid characters if (preg_match('/[\/\\\\:*?"<>|]/', $filename)) { throw FrameworkException::create( ErrorCode::VAL_INVALID_FORMAT, 'Filename contains invalid characters' )->withData([ 'field' => 'filename', 'value' => $filename, 'invalid_chars' => ['/', '\\', ':', '*', '?', '"', '<', '>', '|'], ]); } // Check length if (strlen($filename) > 255) { throw FrameworkException::create( ErrorCode::VAL_INVALID_FORMAT, 'Filename is too long (maximum 255 characters)' )->withData([ 'field' => 'filename', 'length' => strlen($filename), 'max_length' => 255, ]); } } }