見出し画像

[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
>>> 

スクリーンショット 2021-05-25 20.10.53

次に記事のデータ(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,
  }
>>> 

スクリーンショット 2021-05-25 20.21.46

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>

スクリーンショット 2021-05-25 22.38.03

記事のカテゴリーの名前が表示されていますね。

最後に

最後に使った

$post->category->name

は『N+1問題』と呼ばれる問題で、たくさんの数のSQLが実行されて処理に時間がかかる問題を引き起こします。

これについては他の記事で説明します。

今回のソースコード


この記事が気に入ったらサポートをしてみませんか?