1

下午好,

我尝试显示来自AWS S3存储的图像。我使用在AWS S3存储中上传文件时使用的 gaufrette 文件配置。

格弗莱特配置:

knp_gaufrette:
    adapters:
        images:
            aws_s3:
                service_id: "infra.aws_s3.client"
                bucket_name: "%amazon_s3.bucket_name%"
                detect_content_type: true
                options:
                    directory: "%amazon_s3.directories.images%"
                    acl: public-read
        documents:
            aws_s3:
                service_id: "infra.aws_s3.client"
                bucket_name: "%amazon_s3.bucket_name%"
                detect_content_type: true
                options:
                    directory: "%amazon_s3.directories.documents%"
                    acl: public-read
        imports:
            aws_s3:
                service_id: "infra.aws_s3.client"
                bucket_name: "%amazon_s3.bucket_name%"
                detect_content_type: true
                options:
                    directory: "%amazon_s3.directories.imports%"
                    acl: public-read
    filesystems:
        images:
            adapter: images
            alias: images_filesystem
        documents:
            adapter: documents
            alias: documents_filesystem
        imports:
            adapter: imports
            alias: imports_filesystem

控制器代码:

<?php

namespace App\Application\Controller;

use App\Application\Controller\Rest\RestController;
use App\Domain\Entity\BuildingMedia;
use App\Domain\Entity\PropertyPicture;
use App\Infrastructure\Command\Command\CommandBus;
use App\Infrastructure\Repository\BuildingMediaRepository;
use App\Infrastructure\Repository\PropertyPictureRepository;
use Gaufrette\Filesystem;
use Gaufrette\StreamWrapper;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Swagger\Annotations as SWG;
use Nelmio\ApiDocBundle\Annotation\Operation;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;

class MediaController extends RestController
{
    /**
     * @var PropertyPictureRepository
     */
    private $propertyPictureRepository;

    /**
     * @var BuildingMediaRepository
     */
    private $buildingMediaRepository;

    /**
     * @var Filesystem
     */
    private $awsS3;

    /**
     * MediaController constructor.
     *
     * @param PropertyPictureRepository $propertyPictureRepository
     * @param BuildingMediaRepository   $buildingMediaRepository
     * @param Filesystem                $awsS3
     * @param SerializerInterface       $serializer
     * @param CommandBus                $commandBus
     */
    public function __construct(
        PropertyPictureRepository $propertyPictureRepository,
        BuildingMediaRepository $buildingMediaRepository,
        Filesystem $awsS3,
        SerializerInterface $serializer,
        CommandBus $commandBus
    ) {
        $this->propertyPictureRepository = $propertyPictureRepository;
        $this->buildingMediaRepository = $buildingMediaRepository;
        $this->awsS3 = $awsS3;

        parent::__construct($serializer, $commandBus);
    }

    /**
     * @Operation(
     *     tags={"Media"},
     *     summary="Read a property's picture.",
     *     @SWG\Response(
     *         response="200",
     *         description="OK"
     *     ),
     *     @SWG\Response(
     *         response="400",
     *         description="Bad request"
     *     ),
     *     @SWG\Response(
     *         response="401",
     *         description="Unauthorized"
     *     ),
     *     @SWG\Response(
     *         response="403",
     *         description="Access denied"
     *     ),
     *     @SWG\Response(
     *         response="404",
     *         description="Entity not found"
     *     ),
     *     @SWG\Response(
     *         response="500",
     *         description="Internal server error"
     *     )
     * )
     *
     * @ParamConverter("propertyPicture", converter="property_picture")
     *
     * @param PropertyPicture $propertyPicture
     *
     * @return BinaryFileResponse
     */
    public function propertyPictureReadAction(PropertyPicture $propertyPicture): BinaryFileResponse
    {
        $adapter = $this->awsS3->getAdapter();

        $filePath = $adapter->read(
            'group'.DIRECTORY_SEPARATOR.
            $this->getUser()->getGroupId().DIRECTORY_SEPARATOR.
            'property'.DIRECTORY_SEPARATOR.
            $propertyPicture->getProperty()->getIdValue().DIRECTORY_SEPARATOR.
            $propertyPicture->getFilename()
        );

        $response = new BinaryFileResponse($filepath);
        $response->headers->set('Content-Type', 'image/jpeg');
        $response->setContentDisposition(
            ResponseHeaderBag::DISPOSITION_INLINE,
            $propertyPicture->getFilename()
        );

        return $response;
    }
}

如果我尝试使用getLink()from $propertyPicture(该方法返回保存在数据库中的文件 URL),BinaryFileResponse则找不到来自给定 URL 的文件。

我需要从 Gaufrette 获得文件 URL 才能在 API 响应中显示文件。

4

1 回答 1

0

在尝试了许多可能的解决方案后,我找到了这个用于图片的解决方案(即使您在AWS S3中使用私有存储桶,它也能正常工作):

<?php

namespace App\Application\Controller;

use App\Application\Controller\Rest\RestController;
use App\Domain\Entity\BuildingMedia;
use App\Domain\Entity\PropertyPicture;
use App\Infrastructure\Command\Command\CommandBus;
use App\Infrastructure\Repository\BuildingMediaRepository;
use App\Infrastructure\Repository\PropertyPictureRepository;
use Gaufrette\Filesystem;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Response;
use Swagger\Annotations as SWG;
use Nelmio\ApiDocBundle\Annotation\Operation;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpKernel\Exception\HttpException;

class MediaController extends RestController
{
    /**
     * @var PropertyPictureRepository
     */
    private $propertyPictureRepository;

    /**
     * @var BuildingMediaRepository
     */
    private $buildingMediaRepository;

    /**
     * @var Filesystem
     */
    private $awsS3;

    /**
     * MediaController constructor.
     *
     * @param PropertyPictureRepository $propertyPictureRepository
     * @param BuildingMediaRepository   $buildingMediaRepository
     * @param Filesystem                $awsS3
     * @param SerializerInterface       $serializer
     * @param CommandBus                $commandBus
     */
    public function __construct(
        PropertyPictureRepository $propertyPictureRepository,
        BuildingMediaRepository $buildingMediaRepository,
        Filesystem $awsS3,
        SerializerInterface $serializer,
        CommandBus $commandBus
    ) {
        $this->propertyPictureRepository = $propertyPictureRepository;
        $this->buildingMediaRepository = $buildingMediaRepository;
        $this->awsS3 = $awsS3;

        parent::__construct($serializer, $commandBus);
    }

    /**
     * @Operation(
     *     tags={"Media"},
     *     summary="Read a property's picture.",
     *     @SWG\Response(
     *         response="200",
     *         description="OK"
     *     ),
     *     @SWG\Response(
     *         response="400",
     *         description="Bad request"
     *     ),
     *     @SWG\Response(
     *         response="401",
     *         description="Unauthorized"
     *     ),
     *     @SWG\Response(
     *         response="403",
     *         description="Access denied"
     *     ),
     *     @SWG\Response(
     *         response="404",
     *         description="Entity not found"
     *     ),
     *     @SWG\Response(
     *         response="500",
     *         description="Internal server error"
     *     )
     * )
     *
     * @ParamConverter("propertyPicture", converter="property_picture")
     *
     * @param PropertyPicture $propertyPicture
     *
     * @return Response
     */
    public function propertyPictureReadAction(PropertyPicture $propertyPicture): Response
    {
        $adapter = $this->awsS3->getAdapter();

        $content = $adapter->read(
            'group'.DIRECTORY_SEPARATOR.
            $this->getUser()->getGroupId().DIRECTORY_SEPARATOR.
            'property'.DIRECTORY_SEPARATOR.
            $propertyPicture->getProperty()->getIdValue().DIRECTORY_SEPARATOR.
            $propertyPicture->getFilename()
        );

        return new Response($content, 200, array(
                'Content-Type' => 'image/jpeg'
        ));
    }
}

read()from 方法返回文件内容,而Gaufrette不是真实路径。所以,我只需将返回值从BinaryFileResponseto更改为Response并手动设置Content-Type.

下一次升级,如果您有相同的处理是在保存文件时在数据库中设置类型 MIME,并在您需要显示它时返回它,就像来自您的 API 的类似路由一样。

于 2020-03-27T11:11:57.320 回答