Laravel

【Laravel】都道府県のセレクトボックスの実装方法

サムネイル画像
タクマ

こんにちは!タクマです。

31歳未経験からエンジニア転職に成功し、

2021年3月より都内の受託開発企業にてサーバーサイドエンジニアとして働いています!

今回は都道府県のセレクトボックスの実装方法を解説します。

「都道府県のセレクトボックスを実装したい!」

「都道府県のセレクトボックスの実装方法を知りたい!」

という方は、この記事を最後まで読めば、実装方法できるようになりますので、ぜひ、最後まで読んでください!

前提条件

  • Laravel8
  • postsテーブルにprefecture_idというカラムがある。
  • 都道府県マスターデータを入れるテーブルとしてmst_prefecturesテーブルを用意する。
  • PostsモデルとMstPrefecturesモデルの1対多のリレーション。
  • postの作成ページ、編集ページに都道府県のセレクトボックスを設置する。

都道府県マスターテーブルの作成

まずは都道府県のマスターデータとなるテーブルを作成します。

ターミナルで下記のコマンドを入力し、マイグレーションファイルを作成します。

php artisan make:migration create_mst_prefectures_table

マイグレーション ファイルを下記のように編集します。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMstPrefecturesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('mst_prefectures', function (Blueprint $table) {
            $table->id();
            $table->string('name')->unique();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('mst_prefectures');
    }
}

ここでポイントとなるのがunique()と書いてある部分です。

これはユニーク制約と言い、nameカラムに重複した値を格納することを防ぐことができます。

編集したらターミナルでマイグレーションを実行します。

php artisan migrate

シーダーファイルの作成

次にシーダーファイルを作成し、先ほど作成したmst_prefecturesテーブルにデータを入れていきます。

まずはターミナルで下記のコマンドを実行し、シーダーファイルを作成します。

php artisan make:seeder MstPrefectureSeeder

作成されたシーダーファイルを下記のように編集します。

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class MstPrefectureSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $params = [
            ['id' => 1, 'name' => '北海道'],
            ['id' => 2, 'name' => '青森県'],
            ['id' => 3, 'name' => '岩手県'],
            ['id' => 4, 'name' => '宮城県'],
            ['id' => 5, 'name' => '秋田県'],
            ['id' => 6, 'name' => '山形県'],
            ['id' => 7, 'name' => '福島県'],
            ['id' => 8, 'name' => '茨城県'],
            ['id' => 9, 'name' => '栃木県'],
            ['id' => 10, 'name' => '群馬県'],
            ['id' => 11, 'name' => '埼玉県'],
            ['id' => 12, 'name' => '千葉県'],
            ['id' => 13, 'name' => '東京都'],
            ['id' => 14, 'name' => '神奈川県'],
            ['id' => 15, 'name' => '新潟県'],
            ['id' => 16, 'name' => '富山県'],
            ['id' => 17, 'name' => '石川県'],
            ['id' => 18, 'name' => '福井県'],
            ['id' => 19, 'name' => '山梨県'],
            ['id' => 20, 'name' => '長野県'],
            ['id' => 21, 'name' => '岐阜県'],
            ['id' => 22, 'name' => '静岡県'],
            ['id' => 23, 'name' => '愛知県'],
            ['id' => 24, 'name' => '三重県'],
            ['id' => 25, 'name' => '滋賀県'],
            ['id' => 26, 'name' => '京都府'],
            ['id' => 27, 'name' => '大阪府'],
            ['id' => 28, 'name' => '兵庫県'],
            ['id' => 29, 'name' => '奈良県'],
            ['id' => 30, 'name' => '和歌山県'],
            ['id' => 31, 'name' => '鳥取県'],
            ['id' => 32, 'name' => '島根県'],
            ['id' => 33, 'name' => '岡山県'],
            ['id' => 34, 'name' => '広島県'],
            ['id' => 35, 'name' => '山口県'],
            ['id' => 36, 'name' => '徳島県'],
            ['id' => 37, 'name' => '香川県'],
            ['id' => 38, 'name' => '愛媛県'],
            ['id' => 39, 'name' => '高知県'],
            ['id' => 40, 'name' => '福岡県'],
            ['id' => 41, 'name' => '佐賀県'],
            ['id' => 42, 'name' => '長崎県'],
            ['id' => 43, 'name' => '熊本県'],
            ['id' => 44, 'name' => '大分県'],
            ['id' => 45, 'name' => '宮崎県'],
            ['id' => 46, 'name' => '鹿児島県'],
            ['id' => 47, 'name' => '沖縄県'],
        ];
        DB::table('mst_prefectures')->insert($params);
    }
}

次に、シーダーの親ファイルに作成したMstPrefectureSeederを登録します。

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Database\Seeders\MstPrefectureSeeder;

class DatabaseSeeder extends Seeder
{
    /** 実行したいSeederをここに登録 */
    private const SEEDERS = [
        MstPrefectureSeeder::class,
    ];
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        foreach(self::SEEDERS as $seeder) {
            $this->call($seeder);
        }
    }
}

このように親シーダー(DatabaseSeeder)ファイルに登録することで、登録してあるシーダーファイルをコマンド一発で全て実行することができます。

なので、シーダーファイルが増えれば増えるほど、親シーダー(DatabaseSeeder)ファイルに登録しておくと便利になります。

親シーダー(DatabaseSeeder)ファイルに登録が終わったら、シーダーを実行します。

#親シーダー(DatabaseSeeder)ファイルに登録してあるシーダー全てを実行する場合
php artisan db:seed


#特定のシーダーファイルのみを実行する場合
php artisan db:seed --class=MstPrefectureSeeder

シーダーを実行したので、以上でデータの作成が完了しました。

モデルの作成

次にモデルを作成します。

php artisan make:model MstPrefecture

作成されたモデルを下記のように編集します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class MstPrefecture extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
    ];

/**
     * 都道府県に紐付く投稿の取得(Postモデルとのリレーション)
     */
    public function posts()
    {
        return $this->hasMany(post::class, 'prefecture_id', 'id');
    }

}

次にpostモデルにmst_prefectureテーブルとのリレーションを記述します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;


class Post extends Model
{
    use HasFactory;

    protected $fillable = [
     #他のカラム名はあなたのカラム名を書いてください
        'prefecture_id',
    ];

    /**
     * 投稿の都道府県の取得(MstPrefectureモデルとのリレーション)
     */
    public function prefecture()
    {
        return $this->belongsTo(MstPrefecture::class);
    }
}

以上でモデルの作成、およびPostsモデルとMstPrefecturesモデルのリレーションが完了です。

※なおLaravel8においてはリレーション時にuse宣言は必要ありません。参考文献

tinkerにてデータの確認

では、先ほどシーダーで作成したデータが本当に作成されているか見てみましょう。

ターミナルで下記のコードを実行し、tinkerを起動します。

php artisan tinker

#tinkerが起動すると下記のような出力がされます。
Psy Shell v0.10.8 (PHP 8.0.1 — cli) by Justin Hileman
>>> 

tinkerが起動したら下記のコマンドを実行します。

>>> App\Models\MstPrefecture::all();

データが作成されていれば下記のように表示されます。

=> Illuminate\Database\Eloquent\Collection {#4514
     all: [
       App\Models\MstPrefecture {#4515
         id: 1,
         name: "北海道",
         created_at: null,
         updated_at: null,
       },
       App\Models\MstPrefecture {#4516
         id: 2,
         name: "青森県",
         created_at: null,
         updated_at: null,
       },
       App\Models\MstPrefecture {#4517
         id: 3,
         name: "岩手県",
         created_at: null,
         updated_at: null,
       },
       App\Models\MstPrefecture {#4518
         id: 4,
         name: "宮城県",
         created_at: null,
         updated_at: null,
       },
       
       #以下省略

以上でデータの確認ができました。

コントローラーにて都道府県マスターデータの取得

では次にPostControllercreateeditメソッドに記述を追加します。

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\MstPrefecture;


class PostController extends Controller
{
    /**
     * 投稿作成
     * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
     */
    public function create()
    {
        // 都道府県テーブルの全データを取得する
        $prefectures = MstPrefecture::all();

        return view('post.create')
            ->with([
                'prefectures' => $prefectures,
            ]);
    }

    /**
     * 投稿編集
     * @param Request $request
     * @param int
     * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
     */
    public function edit(Post $post)
    {
        // 都道府県テーブルの全データを取得する
        $prefectures = MstPrefecture::all();

        return view('post.edit')
            ->with([
                'prefectures' => $prefectures,
                'post' => $post,
            ]);
    }
}

Viewファイルに都道府県セレクトボックスの設置

ではセレクトボックスを作ります。

postフォルダの中のcreate.blade.phpedit.blade.phpに下記の記述をします。(どちらも下記コードで大丈夫です。)

<div>
    <label>都道府県</label>
    <small class="text-red">※必須</small>
    <select type="text" class="form-control" name="prefecture_id" required>
        <option disabled style='display:none;' @if (empty($post->prefecture_id)) selected @endif>選択してください</option>
        @foreach($prefectures as $pref)
            <option value="{{ $pref->id }}" @if (isset($post->prefecture_id) && ($post->prefecture_id === $pref->id)) selected @endif>{{ $pref->name }}</option>
        @endforeach
    </select>
</div>

上記のコードによってこのようなセレクトボックスができます。

セレクトボックスを開くとこのように都道府県が出てきます。(画像では鳥取県で途切れていますが、ちゃんと沖縄県までありますので、ご心配なく。)

ではコードについて解説していきます。

<option disabled style='display:none;' @if (empty($post->prefecture_id)) selected @endif>選択してください</option>

上記の記述によりcreate.blade.phpではセレクトボックスの初期表示が「選択してください」となります。
でもdisabled style='display:none;によりセレクトボックスの選択肢の中には「選択してください」は表示されません。

<option value="{{ $pref->id }}" @if (isset($institution->prefecture_id) && ($institution->prefecture_id === $pref->id)) selected @endif>{{ $pref->name }}</option>

上記の記述により、edit.blade.phpではセレクトボックスが、保存されている都道府県名を選択した状態になります。

投稿詳細ページでの都道府県名の表示方法

投稿詳細ページでは都道府県名を下記のように表示させることができます。

// $postという変数がコントローラから渡せている前提で

{{ $post->prefecture->name }}

// prefecture_idが1で保存されていたら北海道と表示される

なぜのこの記述で都道府県名を表示させることができるのかと言うと、先ほどMstPrefectureモデルとのリレーションで

/**
     * 投稿の都道府県の取得(MstPrefectureモデルとのリレーション)
     */
    public function prefecture()
    {
        return $this->belongsTo(MstPrefecture::class);
    }

という記述をしているからです。

リレーションとして定義したメソッドは()なしで呼び出すことができます。

さいごに

いかがでしたでしょう?

都道府県のセレクトボックスの実装ができましたでしょうか?

ご質問やご指摘等ある方はコメントしていただければ返信させていただきます。

これからもエンジニアの方、プログラミング初学者の方に役に立つ記事を更新していきますのでよろしくお願いします!

Twitterでも情報発信をしていますので、よかったらフォローをお願いします(^^)

Webエンジニア
タクマ
埼玉県出身の31歳

30歳からプログラミングを始め31歳でWebエンジニアに転職成功。

現在は都内の受託開発企業にてサーバーサイドエンジニアをしています。

\ Follow me /

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA