2023年2月にLaravel10がリリースされます。本日は2023年1月ですので、リリース前です、今回はLaravel10開発版で開発しています。
Livewireとかvueとか目新しいことはせずに、古典的なプログラムでブログシステムを作成しています。↓こんな感じです。
はじめに
Laravel プロジェクトの作成
windowsのコマンドプロンプトあるいはVisualStudioのターミナルで行います。
Laravel10の開発版10.x-devを導入するには、10開発版を指定する必要があります。このようにしてプロジェクトを作成しました。
1 |
composer create-project "laravel/laravel=10.x-dev" lara10 |
通常は(Laravel10リリース)2023年2月7日?以降は、下のコマンドで良いです。
1 |
composer create-project --prefer-dist laravel/laravel lara1 |
1 |
cd lara1 |
作成したディレクトリに移動します。開発用サーバを起動します。
1 |
php artisan serve |
laravelのenvファイル DB設定を DB_DATABASE=lara1 とします。
次にLaravel Breezeを導入するためのお決まりのコマンドを入力します。
composer require laravel/breeze –dev
php artisan breeze:install
php artisan migrate
npm install
npm run dev
ブラウザで http://127.0.0.1:8000/ を叩くと、右上にLogin Regsiter リンクが見えますので、Register リンクを叩いて、以下のように三名 ユーザーアカウントを登録します。
blogsテーブルの作成
blogsテーブルを作成します。
1 |
php artisan make:migration create_blogs_table |
database\migrations\2023_01_08_111831_create_blogs_table.php
作成されたこちらのマイグレーションファイルのカラムを拡張します。
Schema::create(‘blogs’, function (Blueprint $table) {
$table->id();
$table->string(‘title’);
$table->text(‘content’);
$table->string(‘image’);
$table->integer(‘user_id’)->unsigned();
$table->timestamps();
});
タイトルtitle、内容content、画像ファイルのパスimage、投稿者したユーザーID user_idを追加しました。
マイグレーションを実行します。
1 |
php artisan migrate |
BLogモデルを作成します。
1 |
php artisan make:model Blog |
BlogFactoryを作成します。
1 |
php artisan make:factory BlogFactory |
database\factories\BlogFactory.php が生成されますので、BlogFactory.phpを編集します。destinationメソッドのreturn内に以下のように追記します。
1 2 3 4 5 6 7 8 9 10 11 |
public function definition() { return [ 'title' => $this->faker->realText(10), 'content' => $this->faker->realText(60), 'image' => '', 'user_id' => $this->faker->numberBetween($min = 1, $max = 3), 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]; } |
blogsテーブルにダミーデータを挿入
次にダミーデータを作成します。
config/app.php内を日本語対応に変更しておきます。
‘fallback_locale’ => ‘ja’,
‘faker_locale’ => ‘ja_JP’,
‘locale’ => ‘ja’,
BlogsSeederを作成します。
1 |
php artisan make:seeder BlogsSeeder |
database\seeders\BlogsSeeder.php が生成されますので、BlogsSeeder.phpを編集します。
Blog::factory()->count(5)->create();
1 |
php artisan db:seed --class=BlogsSeeder |
ダミーデータの生成を確認しました。画像パスであるimageカラムは空です。
画像ファイルをアップロードできるようにする
publicフォルダにファイルをアップロードできるようにするため、以下のターミナルを実行します。
1 |
php artisan storage:link |
BLogモデルにホワイトリストを設定
app\Models\Blog.php にホワイトリストを設定します。title, content, user_id, image カラムをホワイトリストにします。
1 2 3 4 5 6 7 |
use HasFactory; protected $fillable = [ 'title', 'content', 'user_id', 'image', ]; |
BlogとUserとの間にリレーション設定
blogsテーブル内のカラムuser_idと usersテーブル内のカラムidのリレーションを設定します。
app\Models\Blog.php に以下追加します。
1 2 3 4 |
//リレーション追加 public function user() { return $this->belongsTo(User::class); } |
app\Models\User.php に以下追加します。
1 2 3 4 5 |
// Blogとのリレーションを追加 public function blogs() { return $this->hasMany(Blog::class); } |
Blogコントローラーの作成
BlogControllerを作成します。
1 |
php artisan make:controller BlogController --resource --model=Blog |
app\Http\Controllers\BlogController.php が生成されます。後ほど、index , create , edit などのメソッドを編集します。
Routing の設定
web.phpでルーティングを設定します。routes\web.php に追記します。
1 2 3 4 5 6 7 8 9 10 |
// Route::get('/blogs', 'App\Http\Controllers\BlogController@index')->name('blogs.index'); Route::get('/blogs/create', 'App\Http\Controllers\BlogController@create')->name('blog.create')->middleware('auth'); Route::post('/blogs/store/', 'App\Http\Controllers\BlogController@store')->name('blog.store')->middleware('auth'); Route::get('/blogs/edit/{blog}', 'App\Http\Controllers\BlogController@edit')->name('blog.edit')->middleware('auth'); Route::put('/blogs/edit/{blog}','App\Http\Controllers\BlogController@update')->name('blog.update')->middleware('auth'); Route::delete('/blogs/{blog}','App\Http\Controllers\blogController@destroy')->name('blog.destroy')->middleware('auth'); |
indexメソッド
Blogコントローラーのindexメソッドから編集します。
1 2 3 4 5 6 7 8 |
public function index() { $blogs = Blog::latest()->paginate(3); $auth_user = \Auth::user()->name; return view('index',compact('blogs','auth_user')) ->with('i', (request()->input('page', 1) - 1) * 3); } |
テンプレートファイルを作成します。
resources\views\app.blade.php を作成します。
中身は以下のようになります。Bootstrapのスターターテンプレートを引用しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"> <style type="text/css"> body { font-family: "Hiragino Kaku Gothic ProN","Hiragino Sans",Meiryo,sans-serif; margin-top: 10px !important; } </style> <title>Laravel</title> </head> <body> <div class="container"> <h1 style="font-size:1.75rem;">Laravelシステム</h1> @yield('content') <div><a href="{{ url('./dashboard') }}">dashboard</a></div> </div> </body> </html> |
ブレードファイル resources\views\index.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 |
// @extends('app') @section('content') <a href="{{ url('./blogs/create') }}" class="btn btn-sm btn-primary">登録</a> <div class="w-75"> {!! $blogs->links('pagination::bootstrap-5') !!} @if ($message = Session::get('success')) <div class="alert alert-success"> <p>{{ $message }}</p> </div> @endif </div> <table class="table table-bordered w-75"> @foreach ($blogs as $blog) <tr> <td style="width: 7%;" class="fst-italic">{{ $blog->id }}</td> <td style="width: 20%;"> <img src="{{ Storage::url($blog->image) }}" alt="" class="img-fluid"> </td> <td> <h2 class="fs-5 text-primary">{{ $blog->title}}</h2> {!! nl2br($blog->content) !!} <div class="text-end text-secondary" style="font-size: 0.75rem;">投稿者:{{ $blog->user->name }} 投稿日:{{substr($blog->created_at,0,10)}} 更新日:{{substr($blog->updated_at,0,10)}}</div> <div class="text-end"> @if(Auth::id()==$blog->user_id) <!--<a class="btn btn-sm btn-info" href="{{ route('blog.edit',$blog->id) }} }}"> 変更</a>--> <a class="btn btn-sm btn-success" href="{{ route('blog.edit',[$blog->id, 'page' => request()->input('page')]) }}"> 変更</a> @endif @if(Auth::id()==$blog->user_id) <form action="{{ route('blog.destroy',[$blog->id, 'page' => request()->input('page')]) }}" method="POST" style="display:inline;"> @csrf @method('DELETE') <button type="submit" class="btn btn-sm btn-danger" onclick='return confirm("削除しますか?");'>削除</button> </form> @endif </div> </td> </tr> @endforeach </table> {{$auth_user}} さんがログインしています。 現在のページ番号は、{{ request()->input('page') }}です。 @endsection |
ブラウザでhttp://127.0.0.1:8000/blogsを叩くと、以下のように blogs テーブルの内容が出力されます!
createメソッド
次にブログ記事を新規登録できるようにcreateメソッドを編集します。
createメソッドには、次の一行を追記するのみです。
returnview(‘create’);
ブレードファイル resources\views\create.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 |
// @extends('app') @section('content') <div class="row"> <div class="col-lg-12 margin-tb"> <div class="pull-left"> <h2 style="font-size:1rem;">登録画面</h2> </div> <div class="pull-right"> <a class="btn btn-success" href="{{ url('/blogs') }}">戻る</a> </div> </div> </div> <div style="text-align:right;"> <form action="{{ route('blog.store') }}" method="POST" enctype="multipart/form-data"> @csrf <div class="row w-75"> <div class="col-12 mb-2 mt-2"> <div class="form-group"> <input type="text" name="title" class="form-control" placeholder="タイトル"> </div> </div> <div class="col-12 mb-2 mt-2"> <div class="form-group"> <textarea class="form-control" style="height:100px" name="content" placeholder="内容"></textarea> </div> </div> <div class="col-12 mb-2 mt-2"> <input type="file" name="image" accept=".jpg,.png,image/gif,image/jpeg,image/png"> </div> <div class="col-12 mb-2 mt-2"> <button type="submit" class="btn btn-primary w-100">登録</button> </div> </div> </form> </div> @endsection |
コントローラーのstoreメソッドを以下のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// public function store(Request $request) { $request->validate([ 'title' => 'required', 'content' => 'required', 'image' => 'required', ]); // ディレクトリ名 $dir = 'images'; // imageディレクトリに画像を保存 $path = $request->file('image')->store('public/' . $dir); $blog = new Blog; $blog->title = $request->input(["title"]); $blog->content = $request->input(["content"]); $blog->user_id = \Auth::user()->id; $blog->image = $path; $blog->save(); return redirect()->route('blogs.index') ->with('success','登録しました'); } |
動作確認です。
登録ボタンをクリックすると、登録フォームが表示されますので、内容を入力して登録します。
下画像のように、画像ファイルも含めて無事登録できました!
editメソッド
情報を編集するため、コントローラーのeditメソッドを編集します。投稿者以外が編集できないようにしてあります。
1 2 3 4 5 6 7 8 |
public function edit(Blog $blog) { //$blogs = Blog::all(); if($blog->user_id != \Auth::user()->id){ exit(); } return view('edit',compact('blog')); } |
ブレードファイル resources\views\edit.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 |
// @extends('app') @section('content') <div class="row"> <div class="col-lg-12 margin-tb"> <div class="pull-left"> <h2 style="font-size:1rem;">編集画面</h2> <h3 style="font-size:1rem;">{{ $blog->user->name }} さん投稿者本人だけしか編集できません</h3> </div> <div class="pull-right"> <a class="btn btn-success" href="{{ url('/blogs') }}?page={{ request()->input('page') }}"> ページ番号{{ request()->input('page') }}に戻る</a> </div> </div> </div> <div style="text-align:right;"> <form action="{{ route('blog.update',$blog->id) }}" method="POST" enctype="multipart/form-data"> @method('PUT') @csrf <div class="row w-75"> <div class="col-12 mb-2 mt-2"> <div class="form-group"> <input type="text" name="title" value="{{ $blog->title }}" class="form-control" placeholder="タイトル"> </div> </div> <div class="col-12 mb-2 mt-2"> <div class="form-group"> <textarea class="form-control" style="height:100px" name="content" placeholder="内容">{{ $blog->content }}</textarea> </div> </div> <div class="col-12 mb-2 mt-2"> <input type="file" name="image" accept=".jpg,.png,image/gif,image/jpeg,image/png"> </div> <div class="col-12 mb-2 mt-2"> <input type="hidden" name="page" value="{{ request()->input('page') }}"> <button type="submit" class="btn btn-primary w-100">編集</button> </div> </div> </form> </div> @endsection |
一覧表示のページングで例えば2ページ目の記事を編集します。
編集ボタンをクリックしますと、編集フォームが表示されます。戻るボタンをクリックすると、2ページ目に戻ってくれます。元居た場所に戻るということです。
コントローラーのupdateメソッドを以下のように記載します。
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 update(Request $request, Blog $blog) { $request->validate([ 'title' => 'required', 'content' => 'required', ]); if($request->file('image')){ $dir = 'images'; $path = $request->file('image')->store('public/' . $dir); } $blog->title = $request->input(["title"]); $blog->content = $request->input(["content"]); $blog->user_id = \Auth::user()->id; if($request->file('image')){ $blog->image = $path; } $blog->save(); $page = request()->input('page'); return redirect()->route('blogs.index', ['page' => $page]) ->with('success','更新しました'); } |
動作確認してみます。情報を修正して、画像も選択します。
情報が更新されました!また、画像もアップできています。また、ちゃんと2ページ目に戻ってきています。
destroyメソッド
最後に情報を削除するための destroy メソッドです。
1 2 3 4 5 6 7 8 |
// public function destroy(Blog $blog) { $blog->delete(); $page = request()->input('page'); return redirect()->route('blogs.index', ['page' => $page]) ->with('success',$blog->title.'を削除しました'); } |
割愛しますが、これで削除できます!
Laravel面白いですね。私は、実務でLaravel使っていませんが、Laravelって便利だなーと本当に思いますね。ではでは。