1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravel7タグ付き投稿記事の検索機能(リレーション)

Posted at

やりたいこと

タグを付けて口コミを投稿することができるサイトを作っています。その投稿のタイトルや本文、タグを対象に検索する機能を実装します。検索自体は難しくないかもしれませんが、複数テーブルにまたがるデータを全て検索する必要があるので、ほんの少し厄介でした。でも想像していたより簡単にできました。

前提

データベースは下記の通り、多対多、お互いbelongsToManyのリレーションになっています。
reviews:投稿
tags:タグ
review_tag:中間テーブル

ちなみに
uses:reviewsテーブルと一対多の関係になっている。

環境:Laravel 7

実装!

ビュー1(検索画面)

今回のアプリはヘッダーのコンポーネントに検索を作りました。iタグはFontawesomeの検索虫眼鏡です。

header.blade.php
<form action="{{ url('/search')}}" method="get">
  <i class="fas fa-search"></i>
  <input id="header-search-text" type="search" name="keyword" placeholder="キーワードで検索">
</form>

ボタンは付けませんでしたが、ユーザーがEnterを叩くと送信されます。
URLはmethod属性をgetにすることで、?をセパレータとして、action属性のURLに続けて生成してくれます。参考→https://developer.mozilla.org/ja/docs/Web/HTML/Element/form

ビュー2(検索結果表示)

かなり簡素化してますがコーディング例を下に書いておきます。
親レイアウトとして、views/layouts/myapp.blade.phpを用意しています。
head内、titleタグに@yield('title')というディレクティブを仕込んでいます。
Bladeレイアウトはこちらで→**Laravel7継承レイアウトの基本を図解してみた**

search.blade.php
@extends('layouts.myapp')

@section('title')
「{{$keyword}}」の検索結果
@endsection

@section('main')
<h1 class="main-title">「{{$keyword}}」の検索結果</h1>
@foreach ($reviews as $review)
 <h2>{{$review->live_date}} {{$review->title}}</h2>

 @foreach ($review->tags as $tag)
 <a>{{$tag->tag_name}}</a>
 @endforeach

 <p>{{$review->text}}</p>     
 <span>by {{$review->user->account_name}}さん</span>
<span>{{$review->created_at}}</span>

  @endforeach
  {{ $reviews->links('vendor.pagination.bootstrap-4')}}
@endsection

ルート

web.php
Route::get('search', 'SearchController@search')->name('search');

コントローラ

SearchController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use App\Review;
use App\Tag;
use App\User;

class SearchController extends Controller
{
    public function search(Request $request)
    {

        $keyword = $request->input('keyword');
        if (!empty($keyword))
        { 
            $reviews = Review::where('title', 'like', '%' . $keyword . '%')
            ->orWhere('text', 'like', '%' . $keyword . '%')
            ->orWhereHas('tags', function ($query) use ($keyword){
                $query->where('tag_name', 'like', '%' . $keyword . '%');
            })
            ->paginate(10);
        } else {
            return redirect('/');
        }

        return view('reviews.search', [
            'keyword' => $keyword,
            'reviews' => $reviews
        ]);
    }
}

個人的にポイントは下記です。

  • まずwhereメソッドでreviewテーブルのtitleフィールドで検索かける
  • orWhereメソッドでtextにも検索かける
  • orWhereHasでreviewテーブルにとって多対多の関係にあるtagsテーブルにアクセスし検索をかける
  • where、orWhere、orWhereHasの第2パラメータにlike検索の条件設定をする
  • %記号で前後に検索キーワードの前後に何があってもOKなので、その検索キーワードが引っかかるようになります
  • %を''で囲うのはwhereがパラメータ結合に対応していないため

おしまい

もしご指摘やご質問、うまくいかなかったなどしたら、お気軽にコメントください!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?