Laravel クエリビルダを駆使する

# 目的

- クエリビルダを用いたDBのデータ取得方法とテーブル結合を用いたデータん取得方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.3 | Homwbrewを用いて導入 |
| Laravel バージョン | 7.0.8 | commposerを用いてこちらの方法で導入→[Mac Laravelの環境構築を行う](https://qiita.com/miriwo/items/adaaaeecae69d6392e08) |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homwbrewを用いてこちらの方法で導入→[Mac HomebrewでMySQLをインストールする](https://qiita.com/miriwo/items/ef6a064bc545fbea29d9) |

# 前提環境

- 先に記載した実施環境が構築されていること。
- 実施環境にて何かしらのLaravelアプリが作成されていること。
- Laravelアプリ用のDBが作成され.envファイルに必要情報が記載され、マイグレーションなどが行えること。

# 前提情報

- contentsテーブルとstatusesテーブルを新たに作成し、テーブル内に格納されているデータをクエリビルダを用いて取得する。
- コードの解説は本記事の下部の「ミニ解説」にてちょっとだけ解説している。

# 読後感

- contentsテーブルの内容をクエリビルダを用いて取得する。
- contentsテーブルとstatusesテーブルを結合し内容をクエリビルダを用いて取得する。

# クエリビルダとは？

- LaravelのDBアクセスの手法の一つである。
- クエリ文を先に組み立ててからDBにアクセスする方法である。
- 使用する句はSQLと共通であるが記載方法に若干のクセがある。

# 概要

1. contentテーブルの作成
1. statusesテーブルの作成
1. ルーティングの記載
1. コントローラの作成と記載(クエリビルダの記載)
1. ビューの作成と記載
1. データの格納
1. クエリビルダ単体の確認
1. JOIN句の確認

# 詳細

1. contentテーブルの作成
    1. アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを作成する。

        ```terminal
        $ php artisan make:model Content --migration
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

        ```terminal
        $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php
        ```
    1. 開いたマイグレーションファイルを下記の様に追記修正する。

        ```アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php
        <?php
        
        use Illuminate\Database\Migrations\Migration;
        use Illuminate\Database\Schema\Blueprint;
        use Illuminate\Support\Facades\Schema;
        
        class CreateContentsTable extends Migration
        {
            /**
             * Run the migrations.
             *
             * @return void
             */
            public function up()
            {
                Schema::create('contents', function (Blueprint $table) {
                    $table->id();
                    //下記を追記
                    $table->string('content');
                    $table->integer('status_id');
                    //上記までを追記
                    $table->timestamps();
                });
            }
        
            /**
             * Reverse the migrations.
             *
             * @return void
             */
            public function down()
            {
                Schema::dropIfExists('contents');
            }
        }
        ```
    1. アプリ名ディレクトリで下記コマンドをジックしてマイグレーションを実行する。

        ```terminal
        $ php artisan migrate
        ```
1. statusesテーブルの作成
    1. アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを作成する。

        ```terminal
        $ php artisan make:model Status --migration
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

        ```terminal
        $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_statuses_table.php
        ```
    1. 開いたマイグレーションファイルを下記の様に追記修正する。

        ```アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php
        <?php
        
        use Illuminate\Database\Migrations\Migration;
        use Illuminate\Database\Schema\Blueprint;
        use Illuminate\Support\Facades\Schema;
        
        class CreateContentsTable extends Migration
        {
            /**
             * Run the migrations.
             *
             * @return void
             */
            public function up()
            {
                Schema::create('contents', function (Blueprint $table) {
                    $table->id();
                    //下記を追記
                    $table->string('status_name');
                    $table->timestamps();
                });
            }
        
            /**
             * Reverse the migrations.
             *
             * @return void
             */
            public function down()
            {
                Schema::dropIfExists('contents');
            }
        }
        ```
    1. アプリ名ディレクトリで下記コマンドをジックしてマイグレーションを実行する。

        ```terminal
        $ php artisan migrate
        ```
1. ルーティングの記載
    1. アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

        ```terminal
        $ vi routes/web.php
        ```
    1. 下記の一行を追記する。

        ```アプリ名ディレクトリ/routes/web.php
        Route::get('/output', 'ContentController@output');
        ```
1. コントローラの作成と記載(クエリビルダの記載)
    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。

        ```terminal
        $ php artisan make:controller ContentController
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

        ```terminal
        $ vi app/Http/Controllers/Controller.php
        ```
    1. 下記の様にoutputという名前のアクションを追加する。

        ```アプリ名ディレクトリ/app/Http/Controllers/Controller.php
        <?php
        
        namespace App\Http\Controllers;
        
        use Illuminate\Http\Request;
        //下記を追記
        use App\Content;
        
        class ContentController extends Controller
        {
            //下記を追記
            public function output()
            {
                $contents_query = Content::select('*');
                $contents = $contents_query->get();
                return view('contents.output', [
                    'contents' => $contents,
                ]);
            }
            //上記までを追記
        }
        ```
1. ビューの作成と記載
    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

        ```terminal
        $ mkdir resources/views/contents
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを作成して開く。

        ```terminal
        $ vi resources/views/contents/output.blade.php
        ```
    1. ビューファイルに下記を記載する。

        ```アプリ名ディレクトリ/resources/views/contents/output.blade.php
        @foreach ($contents as $content)
            <hr>
            <p>{{$content['content']}}</p>
            <p>{{$content['status']}}</p>
        @endforeach
        ```
1. データの格納
    1. アプリ名ディレクトリで下記コマンドを実行してtinkerを開く。

        ```terminal
        $ php artisan tinker
        ```
    1. tinkerにて下記を実行してcontentsテーブルにデータを追加する。

        ```php
        use App\Content;
        $a = new Content();
        $a->content = 'test';
        $a->status_id = 1;
        $a->save();
        ```
    1. tinkerにて下記を実行してstatusesテーブルにデータを追加する。

        ```php
        use App\Status;
        $b = new Status();
        $b->status_name = 'good'
        $b->save();
        $c = new Status();
        $c->status_name = 'bad'
        $c->save();
        ```
1. クエリビルダ単体の確認
    1. アプリ名ディレクトリで下記コマンドを実行しローカルサーバを起動する。

        ```terminal
        $ php artisan serve
        ```
    1. 下記にアクセスし、ブラウザから当該アプリを確認する。
        - [http://127.0.0.1:8000/output](http://127.0.0.1:8000/output)

    1. 下記の様にブラウザで表示されることを確認する。

        <img width="589" alt="127_0_0_1_8000_output.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/611b41a2-2c72-9f21-1043-f78839b98a9a.png">

1. JOIN句の確認
    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

        ```terminal
        $ vi app/Http/Controllers/Controller.php
        ```
    1. 開いたコントローラファイルのoutputアクション内部を下記の様に修正する。

        ```アプリ名ディレクトリ/app/Http/Controllers/Controller.php
        <?php
        
        namespace App\Http\Controllers;
        
        use Illuminate\Http\Request;
        use App\Content;
        
        class ContentController extends Controller
        {
            public function output()
            {
                $contents_query = Content::select('*');
                //下記を追記
                $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id');
                $contents = $contents_query->get();
                return view('contents.output', [
                    'contents' => $contents,
                ]);
            }
        }
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを開く。

        ```terminal
        $ vi resources/views/contents/output.blade.php
        ```
    1. ビューファイルに下記を下記の様に修正する。

        ```アプリ名ディレクトリ/resources/views/contents/output.blade.php
        @foreach ($contents as $content)
            <hr>
            <p>{{$content['content']}}</p>
            <!-- 下記を追記 -->
            <p>{{$content['status_name']}}</p>
        @endforeach
        ```
    1. 下記にアクセスし、ブラウザから当該アプリを確認する。
        - [http://127.0.0.1:8000/output](http://127.0.0.1:8000/output)

    1. 下記の様にブラウザで表示されることを確認する。

        <img width="480" alt="127_0_0_1_8000_output.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/7fb5babe-482a-078c-233d-1b32b6607f57.png">

# ミニ解説

### 「クエリビルダ単体の確認」のアクション内のコードについて

- 下記にコントローラのアクションのコードを記載する。

    ```アプリ名ディレクトリ/app/Http/Controllers/Controller.php
    public function output()
    {
        //DBにアクセスするためのクエリ文を組み立てている
        //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している
        $contents_query = Content::select('*');
        //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。
        $contents = $contents_query->get();
        return view('contents.output', [
            'contents' => $contents,
        ]);
    }
    ```

### 「JOIN句の確認」のアクション内のコードについて

- 下記にコントローラのアクションのコードを記載する。

    ```アプリ名ディレクトリ/app/Http/Controllers/Controller.php
    public function output()
    {
        //DBにアクセスするためのクエリ文を組み立てている
        //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している
        $contents_query = Content::select('*');
        //テーブルの結合を行う
        //クエリ文が格納されている変数->join('結合するテーブル名', '結合元テーブル名.結合するカラム名', '=', '結合先テーブル名.リンクするカラム名')
        $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id');
        //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。
        $contents = $contents_query->get();
        return view('contents.output', [
            'contents' => $contents,
        ]);
    }
    ```