diff --git a/eZ/Bundle/EzPublishCoreBundle/Resources/config/routing/internal.yml b/eZ/Bundle/EzPublishCoreBundle/Resources/config/routing/internal.yml index fb948d0f4f..80cf11e8db 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Resources/config/routing/internal.yml +++ b/eZ/Bundle/EzPublishCoreBundle/Resources/config/routing/internal.yml @@ -37,7 +37,7 @@ ez_content_download: ez_content_download_field_id: path: /content/download/{contentId}/{fieldId} - defaults: { _controller: ezpublish.controller.content.download_redirection:redirectToContentDownloadAction } + defaults: { _controller: ezpublish.controller.content.download:downloadBinaryFileByIdAction } requirements: contentId: '\d+' fieldId: '\d+' diff --git a/eZ/Publish/Core/MVC/Symfony/Controller/Content/DownloadController.php b/eZ/Publish/Core/MVC/Symfony/Controller/Content/DownloadController.php index 327c0b6a32..f637b690a4 100644 --- a/eZ/Publish/Core/MVC/Symfony/Controller/Content/DownloadController.php +++ b/eZ/Publish/Core/MVC/Symfony/Controller/Content/DownloadController.php @@ -8,12 +8,13 @@ use eZ\Bundle\EzPublishIOBundle\BinaryStreamResponse; use eZ\Publish\API\Repository\ContentService; +use eZ\Publish\API\Repository\Values\Content\Content; use eZ\Publish\API\Repository\Values\Content\Field; +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; use eZ\Publish\Core\Base\Exceptions\NotFoundException; use eZ\Publish\Core\Helper\TranslationHelper; use eZ\Publish\Core\IO\IOServiceInterface; use eZ\Publish\Core\MVC\Symfony\Controller\Controller; -use InvalidArgumentException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\ResponseHeaderBag; @@ -36,18 +37,51 @@ public function __construct(ContentService $contentService, IOServiceInterface $ } /** - * @param mixed $contentId ID of a valid Content - * @param string $fieldIdentifier Field Definition identifier of the Field the file must be downloaded from - * @param string $filename - * @param \Symfony\Component\HttpFoundation\Request $request + * Download binary file identified by field ID. * - * @return \eZ\Bundle\EzPublishIOBundle\BinaryStreamResponse + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the field $fieldId can't be found, or the translation can't be found. + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If the content is trashed, or can't be found. + * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the user has no access to read content and in case of un-published content: read versions. + */ + public function downloadBinaryFileByIdAction(Request $request, int $contentId, int $fieldId): BinaryStreamResponse + { + $content = $this->contentService->loadContent($contentId); + try { + $field = $this->findFieldInContent($fieldId, $content); + } catch (InvalidArgumentException $e) { + throw new NotFoundException('File', $fieldId); + } + + return $this->downloadBinaryFileAction($contentId, $field->fieldDefIdentifier, $field->value->fileName, $request); + } + + /** + * Finds the field with id $fieldId in $content. + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the field $fieldId can't be found, or the translation can't be found. + */ + protected function findFieldInContent(int $fieldId, Content $content): Field + { + foreach ($content->getFields() as $field) { + if ($field->getId() === $fieldId) { + return $field; + } + } + + throw new InvalidArgumentException( + '$fieldId', + "Field with id $fieldId not found in Content with id {$content->id}" + ); + } + + /** + * Download binary file identified by field identifier. * - * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException - * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException - * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the field $fieldIdentifier can't be found, or the translation can't be found. + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If the content is trashed, or can't be found. + * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the user has no access to read content and in case of un-published content: read versions. */ - public function downloadBinaryFileAction($contentId, $fieldIdentifier, $filename, Request $request) + public function downloadBinaryFileAction(int $contentId, string $fieldIdentifier, string $filename, Request $request): BinaryStreamResponse { if ($request->query->has('version')) { $version = (int) $request->query->get('version'); @@ -70,14 +104,15 @@ public function downloadBinaryFileAction($contentId, $fieldIdentifier, $filename ); if (!$field instanceof Field) { throw new InvalidArgumentException( - "'{$fieldIdentifier}' Field does not exist in Content item {$content->contentInfo->id} '{$content->contentInfo->name}'" + '$fieldIdentifier', + "'{$fieldIdentifier}' field not present on content #{$content->contentInfo->id} '{$content->contentInfo->name}'" ); } $response = new BinaryStreamResponse($this->ioService->loadBinaryFile($field->value->id), $this->ioService); $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, - $filename, + $field->value->fileName, bin2hex(random_bytes(8)) );