概要
- SymfonyでGaufretteを使ってS3に画像をアップロードする
動作環境
- Symfony → v3.4.15
- knp-gaufrette-bundle → v0.5.3
- aws-sdk-php → v3.67.22
全体の流れ
- 各種パッケージのインストール
- serviceに登録
- configで設定
- 画像アップロードクラスの作成
- DI設定
- 画像アップロードクラスをserviceに登録
- 呼び出して使う
各種パッケージのインストール
$ composer require knplabs/knp-gaufrette-bundle
$ composer require aws/aws-sdk-php:^3.0
Serviceに登録
app/config/services.yml
# %hoge% はparameters.ymlで定義した値を使用している
services:
app.aws_s3.client:
class: Aws\S3\S3Client
factory: [Aws\S3\S3Client, 'factory']
arguments:
-
version: 'latest'
region: '%amazon_s3.region%'
credentials:
key: '%amazon_s3.key%'
secret: '%amazon_s3.secret%'
詳しくは下記で確認
https://github.com/KnpLabs/KnpGaufretteBundle/blob/master/Resources/docs/adapters/awss3.md
configでGaufretteの設定
app/config/config.yml
# %hoge% はparameters.ymlで定義した値を使用している
knp_gaufrette:
adapters:
photo_storage:
aws_s3:
service_id: 'app.aws_s3.client'
bucket_name: '%amazon_s3.bucket_name%'
detect_content_type: true
options:
directory: ''
create: true
acl: 'public-read'
# service_idに別名をつけたい場合などに使う
filesystems:
photo_storage:
adapter: 'photo_storage'
alias: 'photo_storage_filesystem'
画像アップロードクラスの作成
src/AppBundle/Service/PhotoUploader.php
<?php
namespace AppBundle\Service;
use Gaufrette\Adapter\AwsS3;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Gaufrette\Filesystem;
/**
* Class PhotoUploader
* @package AppBundle\Service
*/
class PhotoUploader
{
private static $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
private $filesystem;
private $path;
/**
* PhotoUploader constructor.
* @param Filesystem $filesystem
*/
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* Pathのセット(必須)
* @param $path
* @return $this
*/
public function setPath($path)
{
$this->path = $path;
return $this;
}
/**
* @return mixed
*/
public function getPath()
{
return $this->path;
}
/**
* @param UploadedFile $file
* @return bool
*/
public function upload(UploadedFile $file)
{
// 拡張子判定
if (!in_array($file->getClientMimeType(), self::$allowedMimeTypes)) {
throw new \InvalidArgumentException(sprintf('%sは許可されていない形式です', $file->getClientMimeType()));
}
if (!$this->getPath()) {
throw new \UnexpectedValueException('pathがセットされていません');
}
$uploadPath = $this->getPath();
/** @var AwsS3 $adapter */
$adapter = $this->filesystem->getAdapter();
$adapter->setMetadata($uploadPath, array('contentType' => $file->getClientMimeType()));
$result = $adapter->write($uploadPath, file_get_contents($file->getPathname()));
// 戻り値統一のため
return ($result !== false);
}
/**
* @return bool
*/
public function delete()
{
if (!$this->getPath()) {
throw new \UnexpectedValueException('pathがセットされていません');
}
$filePath = $this->getPath();
/** @var AwsS3 $adapter */
$adapter = $this->filesystem->getAdapter();
$result = $adapter->delete($filePath);
return $result;
}
}
サービス登録して使うためにDI設定
既存のservices.ymlはcomposerでインストールしたパッケージ用として使う
src/AppBundle/DependencyInjection/AppExtension.php
<?php
namespace AppBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class AppExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
画像アップロードクラスをサービスに登録
src/AppBundle/Resources/config/services.yml
services:
app.photo_uploader:
class: AppBundle\Service\PhotoUploader
# Aliasを指定(app.aws_s3.clientでもよい)
arguments: ['@photo_storage_filesystem']
コントローラーでの利用サンプル
※ 色々と省略しています(validateとか)
/**
* 製品登録
* @Route("/new", name="product_new")
* @Method({"GET", "POST"})
* @param Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function sampleAction(Request $request)
{
$product = new Product();
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
/** @var Product $product */
$product = $form->getData();
// S3に保存するための画像path設定
/** @var PhotoUploader $uploader */
$uploader = $this->get('app.photo_uploader');
$photo = $product->getPhoto();
$photoPath = 'uploads/photo/product/sample.' . $photo->getClientOriginalExtension();
// upload処理
if ($photo && $photoPath) {
$uploader->setPath($photoPath)->upload($photo);
}
// 以下省略
}