Laravel 5.5 検索機能を実装してみた


この記事では
Laravelでリレーション関係にあるテーブルのカラムから検索ができるようになります!
開発環境は、Laravel5.5 PHP MySQLです。

では早速コードを書いていきましょう!!!
まずは以下2つのマイグレーションファイルを実行し、
recipesテーブルとingredientsテーブルを作成する。

_create_recipes_table.php
<?php

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

class CreateRecipesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('recipes', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->index();
            $table->string('name');
            $table->timestamps();

            // 外部キー制約
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('recipes');
    }
}
_create_ingredients_table.php
<?php

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

class CreateIngredientsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('ingredients', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('recipe_id')->unsigned()->index();
            $table->string('ingredient', 255);
            $table->timestamps();

            // 外部キー制約
            $table->foreign('recipe_id')->references('id')->on('recipes')->onDelete('cascade');
        });
    }

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

次にRecipeモデルとIngredientモデルを作成し、一対多のリレーション関係を作る。
(今回Userモデルについては割愛します。)

Recipe.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Recipe extends Model
{
    protected $fillable = ['user_id', 'name'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function ingredients()
    {
        return $this->hasMany(Ingredient::class);
    }
}
Ingredient.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Ingredient extends Model
{
    protected $fillable = ['recipe_id', 'ingredient'];

    public function recipe()
    {
        return $this->belongsTo(Recipe::class);
    }
}

検索フォームへのルーティングを付け加えます。

/routes/web.php
//検索機能
Route::get('paginate', 'SearchController@index')->name('search.index');

検索機能に使うコントローラーを作成し、以下のように編集します。

/Controllers/SearchController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; //付け加える

use App\Recipe;//付け加える

class SearchController extends Controller
{
    public function index(Request $request)
    {
        //キーワードを取得
        $keyword = $request->input('keyword');

        //もしキーワードが入力されている場合
        if(!empty($keyword))
        {   
            //料理名から検索
            $recipes = DB::table('recipes')
                    ->where('name', 'like', '%'.$keyword.'%')
                    ->paginate(4);

            //リレーション関係にあるテーブルの材料名から検索
            $recipes = Recipe::whereHas('ingredients', function ($query) use ($keyword){
                $query->where('ingredient', 'like','%'.$keyword.'%');
            })->paginate(4);

        }else{//キーワードが入力されていない場合
            $recipes = DB::table('recipes')->paginate(4);
        }
        //検索フォームへ
        return view('search.index',[
            'recipes' => $recipes,
            'keyword' => $keyword,
            ]);
    }
}
/search/index.blade.php
   //検索フォーム
   <div class="container">
       <div class="row">
            <div class="col-md-3">   
                <form class="form-inline">
                    <div class="form-group">
                    <input type="text" name="keyword" value="{{ $keyword }}"
                    placeholder="料理名か材料名を入力">
                    <input type="submit" value="検索" >
                    </div>
                </form>
            </div>
        </div>
    </div>

    //料理名の表示
    <div class="container">
        @if(count($recipes) > 0)
          <div class="row">
            @foreach($recipes as $recipe)
            <div class="col-md-3">
              {{ $recipe->name }}
            </div>
            @endforeach
           </div>
        @endif
                //ページネーション機能
        <div class="paginate">
            {{ $recipes->render('pagination::bootstrap-4') }}
        </div>
     </div>

以上で簡単な検索機能の完成です!
検索フォームで料理名か材料名を入力するとその条件にあった料理名が表示されます!
今回はシンプルな作りですが、これに加えて写真や料理コメントなどを付け加えるといいかもしれないですね!

参考文献
https://readouble.com/laravel/5.5/ja/queries.html#pessimistic-locking
https://readouble.com/laravel/5.5/ja/eloquent-relationships.html#querying-relationship-existence
https://readouble.com/laravel/5.5/ja/pagination.html

閲覧ありがとうございました!