AWSのアクセスキーを取得
※IAMが作成されている前提です。
AWSコンソール画面に行き、IAMを選択します。サイドバーのユーザーを選択し、任意のユーザーを選択します。
セキュリティ認証情報のタブからアクセスキーの欄に行き、アクセスキーを作成するをクリックします。
※アクセスキーは一度しか表示されないので.envファイルに貼り付けてください。
.env
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
バケット作成
S3からバケットを作成します。
一意のバケット名を入力
パブリックアクセスを全てブロックを外します
その他はデフォルトの設定でいいです。
そして下部までいってバケットを作成ボタンを押してください。
エラー時の対応
ポリシーの設定を行わないと画像にアクセスした際に権限エラーとなります。
ポリシーの設定
バケット->アクセス許可 からバケットポリシーを設定します。
ポリシージェネレーターをクリックします。
- Step1。Select Type of Policyを S3 Bucket Polictにします。
- Step2。Prubcipalに* を入力します。
- Step3。ActionsからGetObjectとGetObjectVersionを選択します。
- Step4。ARMを入力してください。最後尾に/* をつけることを忘れないでください。
{
"Version": "2012-10-17",
"Id": "Policy********",
"Statement": [
{
"Sid": "Stmt********",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::hoge/*"
}
]
}
実装
AWS_ACCESS_KEY_ID=取得したアクセスキー
AWS_SECRET_ACCESS_KEY=取得したシークレットキー
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=作成したバケット名
AWS_USE_PATH_STYLE_ENDPOINT=false
Laravel-medialibraryを導入
composer require "spatie/laravel-medialibrary"
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider"
php artisan migrate
flysystem-aws-s3を導入
composer require league/flysystem-aws-s3-v3:^3.0
モデルに記述
使用するモデルにHasMedia
とInteractsWithMedia
をインポートします。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class User extends Model implements HasMedia //こちら
{
use InteractsWithMedia;//こちら
}
View
<form class="space-y-6" action="{{ route('user.image_upload') }}" method="POST" enctype="multipart/form-data" >
@method('PUT')
<div class="col-span-full">
<label for="cover-photo" class="block text-sm font-medium leading-6 text-gray-900">画像</label>
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 px-6 py-10">
<div class="text-center">
<svg class="mx-auto h-12 w-12 text-gray-300" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z" clip-rule="evenodd" />
</svg>
<div>
<label for="image">画像を選択:</label>
<input type="file" id="image" name="image" accept="image/*">
</div>
<div class="file-name" id="file-name">選択されたファイル: なし</div>
<p class="text-xs leading-5 text-gray-600">PNG, JPG, GIF up to 10MB</p>
</div>
</div>
</div>
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
追加
</button>
</form>
ルートを作成
Route::controller(UserImageController::class)->group(function () {
Route::get('image/create', 'index')->name('user.image_upload_form');
Route::post('image/store', 'store')->name('user.image_upload');
});
コントローラーを作成
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class UserImageController extends Controller
{
/**
* 画像追加フォームを表示
*/
public function create(): View
{
return view('user.image_upload');
}
/**
* 商品を追加する
*/
public function store(Request $request)
{
$validated = $request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg',
]);
$image = User::create($validated);
// メディアの追加
if ($request->hasFile('image')) {
$filePath = Str::uuid() . '.' . $request->file('image')->getClientOriginalExtension();
$item->addMediaFromRequest('image')
->usingFileName($filePath)
->toMediaCollection('images', 's3');
}
return redirect()->route('user.image_upload_form');
}
}
このままですと、[id]/ファイル名のように作成されてしまいます。今回の意図はコレクション名/ファイル名で保存したいのでカスタムパスジェネレーターを作成して設定を行います。
Laravel Medialibrary の設定ファイルを作成
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="config"
カスタムパスジェネレータを作成
<?php
namespace App\PathGenerators;
use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Illuminate\Support\Str;
class CustomPathGenerator implements PathGenerator
{
/**
* メディアファイルの基本パスを取得します。
*
* @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
* @return string
*/
public function getPath(Media $media): string
{
// モデルの短縮クラス名(例: 'User')を取得
$modelName = class_basename($media->model);
// モデル名を複数形に変換し、小文字にする(例: 'users')
$folderName = Str::plural(Str::snake($modelName));
return "{$folderName}/";
}
/**
* メディアの変換ファイルのパスを取得します。
*
* @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
* @return string
*/
public function getPathForConversions(Media $media): string
{
$modelName = class_basename($media->model);
$folderName = Str::plural(Str::snake($modelName));
return "{$folderName}/conversions/";
}
/**
* レスポンシブ画像のパスを取得します。
*
* @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
* @return string
*/
public function getPathForResponsiveImages(Media $media): string
{
$modelName = class_basename($media->model);
$folderName = Str::plural(Str::snake($modelName));
return "{$folderName}/responsive/";
}
}
カスタムパスジェネレータを登録
configmedia-library.php
<?php
return [
'path_generator' => App\PathGenerators\CustomPathGenerator::class,
]
表示の仕方
@if($recruit->hasMedia('images')
<img src="{{ $recruit->getFirstMediaUrl('images') }}" class="w-32 h-32 object-contain">
@endif
## 更新処理
```php
public function update(Request $request, User $user)
{
$validated = $request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg',
]);
$user->update($validated);
// メディアの更新
if ($request->hasFile('image')) {
// 既存の画像を削除(オプション)
if ($user->hasMedia('images')) {
$user->clearMediaCollection('images');
}
// 新しい画像をアップロード
$user->addMediaFromRequest('image')
->usingFileName(Str::uuid() . '.' . $request->file('image')->getClientOriginalExtension())
->toMediaCollection('images', 's3');
}
}