Gaufrette(使用 AWS)和 Symfony 4 - 阅读图片

Gaufrette (with AWS) & Symfony 4 - Read a picture

下午好,

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

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;
    }
}

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

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

在尝试了许多可能的解决方案后,我找到了这个用于图片的解决方案(即使您在 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()方法从Gaufrettereturns文件内容,而不是真实路径。所以,我刚刚将 returns 值从 BinaryFileResponse 更改为 Response 并手动设置了 Content-Type.

下一次升级,如果你有相同的处理是在保存文件时在数据库中设置 MIME 类型,returns 当你需要像从你的 API.