adminの管理画面を作って、ファイルアップロード機能を追加。一般ユーザがダウンロードできるようにしてみる。
前回の続き
laravel8 + breezeで一般ユーザ・管理者のログインを分けてみる(usersテーブルに管理者フラグを追加するだけ)
1, welcome.blade.phpをコピペして、admin.blade.phpを作る
2, /adminに表示されるようにする。
routes/web.php
1 2 3 4 5 6 |
// admin以下は管理者のみアクセス可 Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'can:admin']], function () { Route::get('/', function () { return view('admin'); }); }); |
3, 管理者以外のユーザ一覧を表示する。
ふと思ったけど、laravel8のuserは、modelもmigrationも最初から用意されているのに、なぜUsercontrollerだけ無いのだろうか…。
1 2 3 4 |
php artisan make:controller AdminController --resource # コントローラー名は単数形で、最初は大文字。間違えたら削除して作り直し。クラス名を変更したり削除したら以下のコマンドで作り直し composer dump-autoload |
AdminController.php
1 2 3 4 5 6 7 8 9 10 |
use app\Models\User; // userモデル class AdminController extends Controller { public function index() { // 管理者以外のユーザ一覧を取得 $users = User::WHERE('admin', false)->orderby('created_at', 'desc')->get(); return view('admin', compact('users')); } |
web.phpを書き換え
1 2 3 4 5 |
use App\Http\Controllers\AdminController; // admin以下は管理者のみアクセス可 Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'can:admin']], function () { Route::resource('/', AdminController::class); }); |
admin.blade.phpで、ユーザ一覧をテーブル表示する。
tailwind.cssを使ってみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> ユーザー一覧 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 bg-white border-b border-gray-200"> <table class="table-auto"> <thead> <tr> <th class="px-4 py-2">名前</th> <th class="px-4 py-2">メールアドレス</th> <th class="px-4 py-2">作成日</th> </tr> </thead> <tbody> @foreach($users as $user) <tr> <td class="border px-4 py-2">{{$user->name}}</td> <td class="border px-4 py-2">{{$user->email}}</td> <td class="border px-4 py-2">{{$user->created_at}}</td> </tr> @endforeach </tbody> </table> </div> </div> </div> </div> |
4, 管理画面からファイルのアップロード機能を追加する。
1 |
php artisan make:model Upload -a |
migrate
1 2 3 4 5 6 7 8 9 10 11 |
public function up() { Schema::create('uploads', function (Blueprint $table) { $table->id(); $table->string('title')->comment('タイトル'); $table->string('detail')->comment('詳細'); $table->string('file_path')->comment('アップロードされたファイルのパス'); $table->string('file_name')->comment('ハッシュ化される前のファイル名'); $table->timestamps(); }); } |
UploadController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public function store(Request $request) { // フォームの入力の値をチェック $validated = $request->validate([ 'title' => 'required|unique:uploads|max:255', 'detail' => 'required|max:255', 'file' => 'required|file', ]); // ファイルそのものはWebサーバに保存 $file_name = $request->file('file')->getClientOriginalName(); //$file_path = Storage::putFile('/uploads', $request->file('file'), 'public'); $upload_file = $request->file('file'); $file_path = $upload_file->store('uploads',"public"); // ファイル名とパスは、DBに保存する。 $upload = new Upload(); $upload->title = $request->input('title'); $upload->detail = $request->input('detail'); $upload->file_name = $file_name; $upload->file_path = $file_path; $upload->save(); // 前の画面に戻る return back(); } |
admin.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
<x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> {{ __('Dashboard') }} </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> ファイル一覧 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 bg-white border-b border-gray-200"> @if (count($errors) > 0) <div> <div class="font-medium text-red-600"> {{ __('Whoops! Something went wrong.') }} </div> <ul class="mt-3 list-disc list-inside text-sm text-red-600"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif {{-- post先はname指定。resourceで自動生成される。php artisan route:listで確認 --}} <form method="POST" action="{{route('upload.store')}}" method="POST" enctype="multipart/form-data"> @csrf <input type="text" name="title" value="{{old('title')}}" placeholder="タイトル"> <input type="text" name="detail" value="{{old('detail')}}" placeholder="詳細"> <input type="file" name="file"> <input type="submit" value="アップロード"> </form> <table class="table-auto"> <thead> <tr> <th class="px-4 py-2">タイトル</th> <th class="px-4 py-2">詳細</th> <th class="px-4 py-2">ファイル名</th> <th class="px-4 py-2">作成日</th> </tr> </thead> <tbody> @foreach($uploads as $upload) <tr> <td class="border px-4 py-2">{{$upload->title}}</td> <td class="border px-4 py-2">{{$upload->detail}}</td> <td class="border px-4 py-2">{{$upload->file_name}}</td> <td class="border px-4 py-2">{{$upload->created_at}}</td> </tr> @endforeach </tbody> </table> </div> </div> ユーザー一覧 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 bg-white border-b border-gray-200"> <table class="table-auto"> <thead> <tr> <th class="px-4 py-2">名前</th> <th class="px-4 py-2">メールアドレス</th> <th class="px-4 py-2">作成日</th> </tr> </thead> <tbody> @foreach($users as $user) <tr> <td class="border px-4 py-2">{{$user->name}}</td> <td class="border px-4 py-2">{{$user->email}}</td> <td class="border px-4 py-2">{{$user->created_at}}</td> </tr> @endforeach </tbody> </table> </div> </div> </div> </div> </x-app-layout> |
5, ログインした一般ユーザから一覧表示&ログインできるようにする
1 |
php artisan make:controller UserController --resource |
app/Http/Controllers/Auth/AuthenticatedSessionController.phpで、ログイン後のリダイレクト先を指定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public function store(LoginRequest $request) { $request->authenticate(); $request->session()->regenerate(); // 管理者だったら、ログイン後に/adminにリダイレクト if (Auth::User()->admin == true) { return redirect('/admin'); }else{ return redirect('/'); } //return redirect()->intended(RouteServiceProvider::HOME); } |
app/Http/Controllers/Auth/RegisteredUserController.phpで、新規作成ユーザの自動ログイン後のリダイレクト先も変更しておく。
1 2 3 4 5 6 7 8 9 |
public function store(Request $request) { //...... Auth::login($user); return redirect('/user'); // return redirect(RouteServiceProvider::HOME); } |
routes/web.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
use App\Http\Controllers\UserController; use App\Http\Controllers\AdminController; use App\Http\Controllers\UploadController; // admin以下は管理者のみアクセス可 Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'can:admin']], function () { Route::resource('/upload', UploadController::class); Route::resource('/', AdminController::class); }); // ログインした一般ユーザ Route::group(['prefix' => '/user', 'middleware' => ['auth']], function () { Route::resource('/', UserController::class); }); Route::get('/', function () { return view('welcome'); }); Route::get('/dashboard', function () { return view('dashboard'); })->middleware(['auth'])->name('dashboard'); |
忘れがち!
1 2 |
# /public内にシンボリックリンクstorage(/storage/app/publicへのリンク)が作られる php artisan storage:link |
resources/views/user.blade.php(admin.blade.phpをコピペ)
aタグにdownload属性をつけるのがミソ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> {{ __('Dashboard') }} </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> ファイル一覧 <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 bg-white border-b border-gray-200"> <table class="table-auto"> <thead> <tr> <th class="px-4 py-2">タイトル</th> <th class="px-4 py-2">詳細</th> <th class="px-4 py-2">ファイル名</th> <th class="px-4 py-2">作成日</th> </tr> </thead> <tbody> @foreach($uploads as $upload) <tr> <td class="border px-4 py-2">{{$upload->title}}</td> <td class="border px-4 py-2">{{$upload->detail}}</td> <td class="border px-4 py-2"> <a href="storage/{{$upload->file_path}}" download> {{$upload->file_name}} </a> </td> <td class="border px-4 py-2">{{$upload->created_at}}</td> </tr> @endforeach </tbody> </table> </div> </div> </div> </div> </x-app-layout> |
一応できたけど、これだとURLを知っている人は誰でもダウンロード出来ちゃうな…。