![見出し画像](https://assets.st-note.com/production/uploads/images/53119140/rectangle_large_type_2_c07e7ce77eb228ad157f2251f7c29864.png?width=1200)
[laravel8] ブログのカテゴリー追加
以前の記事で
ブログの記事を表示するところまで実装しました。
後にカテゴリーでまとめて記事を表示できるようにするために、この記事ではブログにカテゴリーを追加していきます。
マイグレーション&モデル 生成
カテゴリーを格納するためのテーブルを追加するためのマイグレーションファイルとそのテーブルを操作するためのモデルを生成していきます。
マイグレーションのファイル生成コマンド
$php artisan make:migration create_categories_table
このテーブルを操作するモデルを生成するコマンド
$php artisan make:model Category
のように2回に分けてコマンドを実行しましたが、次のように1つのコマンドでも実行できます。
$php artisan make:model Category -m
Model created successfully.
Created Migration: 2021_05_25_102102_create_categories_table
$
以下の二つのファイルが生成されました。
・app/Models/Category.php
・database/migrations/2021_05_25_102102_create_categories_table.php
マイグレーション
database/migrations/2021_05_25_102102_create_categories_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', functio(Blueprint $table){
$table->id();
$table->string('name'); // カテゴリー名
$table->string('slug'); // URLで使用するスラッグ
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}
ブログの記事にもカテゴリーを紐づける必要があるので以前に作成したpostsテーブルを作ったマイグレーションファイルも編集する。
database/migrations/2021_05_07_111050_create_posts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', functio(Blueprint $table) {
$table->id();
$table->foreignId('category_id'); // category idを追加
$table->string('slug')->unique();
$table->string('title');
$table->text('excerpt');
$table->text('body');
$table->timestamps();
$table->timestamp('published_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
freshコマンドを実行してテーブルを再び作成(データは全部消える)
$php artisan migrate:fresh
データ追加
tinkerを使いカテゴリーのデータを挿入
$php artisan tinker
Psy Shell v0.10.8 (PHP 8.0.3 — cli) by Justin Hileman
>>> use App\Models\Category;
>>> $category = new Category;
=> App\Models\Category {#3341}
>>> $category->name = 'Personal';
=> "Personal"
>>> $category->slug = 'personal';
=> "personal"
>>> $category->save();
=> true
>>> $category = new Category;=> App\Models\Category {#3342}
>>> $category->name = 'Work';=> "Work"
>>> $category->slug = 'work';=> "work"
>>> $category->save();=> true
>>> $category = new Category; => App\Models\Category {#3352}
>>> $category->name = 'Hobbies';
=> "Hobbies"
>>> $category->slug = 'hobbies';
=> "hobbies"
>>> $category->save();
=> true
>>>
次に記事のデータ(posts)も挿入します。
>>> use App\Models\Post;
>>> Post::create([ 'title' => 'My Family Post', 'excerpt' => 'Excerpt for my family post', 'body' => 'body for my family post', 'slug' => 'my-family-post', 'category_id' => 1 ]);
=> App\Models\Post {#4295
title: "My Family Post",
excerpt: "Excerpt for my family post",
body: "body for my family post",
slug: "my-family-post",
category_id: 1,
updated_at: "2021-05-25 11:17:49",
created_at: "2021-05-25 11:17:49",
id: 1,
}
>>> Post::create([ 'title' => 'My Work Post', 'excerpt' => 'Excerpt for my work post', 'body' => 'body for my work post', 'slug' => 'my-work-post', 'category_id' => 2 ]);
=> App\Models\Post {#4133
title: "My Work Post",
excerpt: "Excerpt for my work post",
body: "body for my work post",
slug: "my-work-post",
category_id: 2,
updated_at: "2021-05-25 11:19:31",
created_at: "2021-05-25 11:19:31",
id: 2,
}
>>> Post::create([ 'title' => 'My Hobby Post', 'excerpt' => 'Excerpt for my hobby post', 'body' => 'body for my hobby post', 'slug' => 'my-hobby-post', 'category_id' => 3 ]);
=> App\Models\Post {#4299
title: "My Hobby Post",
excerpt: "Excerpt for my hobby post",
body: "body for my hobby post",
slug: "my-hobby-post",
category_id: 3,
updated_at: "2021-05-25 11:20:16",
created_at: "2021-05-25 11:20:16",
id: 3,
}
>>>
Eloquent Relationships
tinkerを使って記事データを取得してみます。
>>> use App\Models\Post;
>>> $post = Post::first();
=> App\Models\Post {#4071
id: 1,
category_id: 1,
slug: "my-family-post",
title: "My Family Post",
excerpt: "Excerpt for my family post",
body: "body for my family post",
created_at: "2021-05-25 11:17:49",
updated_at: "2021-05-25 11:17:49",
published_at: null,
}
category_idを追加しているので取得したデータにcategory_idが入っているのがわかりますが、カテゴリーのデータが入っているわけではありません。
ここでカテゴリーのデータを取得できるようにPostモデルでEloquent relationshipを定義します。
Postモデルにcategoryメソッドを追加します。Relationship(関係)は記事がカテゴリーに属して(belongs to)いるのでbelongsToを使用します。
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $guarded = [];
public function category()
{
return $this->belongsTo(Category::class);
}
}
postからcategoryを取得
再びtinkerを使って記事からカテゴリを取得してみます。
>>> $post = App\Models\Post::first();
=> App\Models\Post {#4066
id: 1,
category_id: 1,
slug: "my-family-post",
title: "My Family Post",
excerpt: "Excerpt for my family post",
body: "body for my family post",
created_at: "2021-05-25 11:17:49",
updated_at: "2021-05-25 11:17:49",
published_at: null,
}
>>> $post->category;
=> App\Models\Category {#3661
id: 1,
name: "Personal",
slug: "personal",
created_at: "2021-05-25 11:02:32",
updated_at: "2021-05-25 11:02:32",
}
$post->category
でカテゴリのデータが取得できていることがわかります。
この記事のカテゴリの名前を取得するには
>>> $post->category->name;
=> "Personal"
viewに適用
resources/views/posts.blade.php
<x-layout>
@foreach($posts as $post)
<article>
<h1>
<a href="/posts/{{ $post->slug}}" >
{{ $post->title }}
</a>
</h1>
<p>
<a href="#">{{ $post->category->name }}</a>
</p>
<div>
{{ $post->excerpt }}
</div>
</article>
@endforeach
</x-layout>
記事のカテゴリーの名前が表示されていますね。
最後に
最後に使った
$post->category->name
は『N+1問題』と呼ばれる問題で、たくさんの数のSQLが実行されて処理に時間がかかる問題を引き起こします。
これについては他の記事で説明します。
今回のソースコード
この記事が気に入ったらサポートをしてみませんか?