1
1

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 1 year has passed since last update.

【Laravel】キーワード検索機能 + 都道府県プルダウン

Last updated at Posted at 2022-04-19

0. はじめに

大阪のLaravel初学者サウナーこと、kazumakishimoto(@kazuma_dev)です!
Laravelでクエリビルダ/ローカルスコープ/ページネーションを使用した、都道府県プルダウン&キーワード検索機能の解説です!

0-1. 全体の流れ

1.都道府県プルダウン&キーワード検索機能
2.補足
Reference

0-2. 本記事の対象者

  • Laravelのキーワード検索機能
  • 都道府県プルダウン機能

0-3. 事前準備

configフォルダ

config/pref.php
<?php

return [
    '0' => '未選択',
    '1' => '北海道',
    '2' => '青森県',
    '3' => '岩手県',
    '4' => '宮城県',
    '5' => '秋田県',
    '6' => '山形県',
    '7' => '福島県',
    '8' => '茨城県',
    '9' => '栃木県',
    '10' => '群馬県',
    '11' => '埼玉県',
    '12' => '千葉県',
    '13' => '東京都',
    '14' => '神奈川県',
    '15' => '新潟県',
    '16' => '富山県',
    '17' => '石川県',
    '18' => '福井県',
    '19' => '山梨県',
    '20' => '長野県',
    '21' => '岐阜県',
    '22' => '静岡県',
    '23' => '愛知県',
    '24' => '三重県',
    '25' => '滋賀県',
    '26' => '京都府',
    '27' => '大阪府',
    '28' => '兵庫県',
    '29' => '奈良県',
    '30' => '和歌山県',
    '31' => '鳥取県',
    '32' => '島根県',
    '33' => '岡山県',
    '34' => '広島県',
    '35' => '山口県',
    '36' => '徳島県',
    '37' => '香川県',
    '38' => '愛媛県',
    '39' => '高知県',
    '40' => '福岡県',
    '41' => '佐賀県',
    '42' => '長崎県',
    '43' => '熊本県',
    '44' => '大分県',
    '45' => '宮崎県',
    '46' => '鹿児島県',
    '47' => '沖縄県'
];

0-4. 使用画像のイメージ

image.png

1. 都道府県プルダウン&キーワード検索機能

1-1. Route

routes/web.php
# 検索機能
Route::get('/search', 'ArticleController@search')->name('articles.search');

1-2. Migration

$ php artisan make:model Article --migration
database/migrations/XXXXXXXXXXX_create_articles_table.php
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('user_id')->unsigned();
            $table->bigInteger('pref_id')->nullable();
            $table->text('title');
            $table->text('body');
            $table->string('image')->nullable();
            $table->timestamps();
            $table->softDeletes();

            $table->foreign('user_id')
            ->references('id')
            ->on('users')
            ->onDelete('cascade');

        });
    }
$ php artisan migrate

1-3. Model

  • クエリビルダのwhereメソッド('カラム名','比較演算子',"部分一致の値")
app/Models/Article.php
    protected $fillable = [
        'pref_id', 'title', 'body', 'image',
    ];

    public function getPrefNameAttribute()
    {
        return config('pref.' . $this->pref_id);
    }

    public function scopeSearchFilter($query, string $search = null)
    {
        if (!$search) {
            return $query;
        }

        return $query->where('title', 'LIKE', "%{$search}%")
        ->orWhere('body', 'LIKE', "%{$search}%");
    }

    public function scopePrefFilter($query, string $pref = null)
    {
        if (!$pref) {
            return $query;
        }

        return $query->where('pref_id', $pref);
    }

1-4. Controller

$ php artisan make:controller ArticleController
  • get()paginate()に変更
php:app/Http/Controllers/ArticleController.php
<?php

namespace App\Http\Controllers;

use App\Models\Article;
use App\Http\Requests\ArticleRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

//略

    // 投稿一覧
    public function index()
    {
        $articles = Article::query()
            ->with(['user', 'likes', 'tags', 'comments'])
            ->orderBy('created_at', 'desc')
            ->paginate(15);

        $data = [
            'articles' => $articles,
        ];

        return view('articles.index', $data);
    }

    // 投稿画面
    public function create()
    {
        $prefs = config('pref');

        $user = Auth::user();

        $data = [
            'user' => $user
        ];

        return view('articles.create', $data)->with(['prefs' => $prefs]);
    }

    // 投稿処理
    public function store(ArticleRequest $request, Article $article)
    {
        $article->user_id = $request->user()->id;
        $all_request = $request->all();
        $article->pref_id = $request->pref;
        $article->fill($all_request)->save();

        return redirect()->route('articles.index');
    }

    // 検索機能
    public function search(Request $request)
    {
        $articles = Article::searchFilter($request->search)
            ->prefFilter($request->pref)
            ->orderBy('created_at', 'desc')
            ->with(['user', 'likes', 'tags'])
            ->paginate(10);

        $data = [
            'articles' => $articles,
        ];

        return view('articles.index', $data);
    }

1-5. View

resources/views/articles/card.blade.php
@if($article->pref_id !== 0)
<div class="ml-2 d-flex align-items-center">
    <a href="{{ route('articles.search', ['pref' => $article->pref_id]) }}" class="text-muted"><i class="fas fa-map-marker-alt p-1"></i>{{ $article->prefName }}</a>
</div>
@endif
resources/views/articles/create.blade.php
<form method="POST" action="{{ route('articles.store', ['article' => $article]) }}" enctype="multipart/form-data">
    @method('PATCH')
    <div class="form-group">
        <label for="pref">所在地</label>
        <select class="form-control" id="pref" name="pref">
            @foreach($prefs as $key => $score)
            <option value="{{ $key }}">{{ $score }}</option>
            @endforeach
        </select>
    </div>
    <button type="submit" class="btn blue-gradient btn-block">更新する</button>
</form>
resources/views/nav.blade.php
<form method="GET" action="{{ route('articles.search') }}" class="d-flex">
    <select class="form-control" id="pref" name="pref">
        @foreach(config('pref'); as $key => $score)
        <option value="{{ $key }}">{{ $score }}</option>
        @endforeach
    </select>
    <input class="form-control" name="search" type="text" placeholder="検索..." aria-label="Search">
    <button class="input-group-text border-0" type="submit"><i class="fas fa-search"></i></button>
</form>
resources/views/articles/index.blade.php
<div class="paginate">
    {{ $articles->appends(request()->input())->links() }}
</div>

2. 補足

2-1. 開発環境(FW/ツールのバージョンなど)

ツール バージョン
Vue.js 2.6.14
jQuery 3.4.1
PHP 7.4.1
Laravel 6.20.43
MySQL 5.7.36
Nginx 1.18.0
Composer 2.0.14
npm 6.14.6
Git 2.33.1
Docker 20.10.11
docker-compose v2.2.1
PHPUnit 8.0
CircleCI 2.1
heroku 7.59.4
MacBook Air M1,2020
macOS Monterey 12.3
Homebrew 3.3.8

2-2. ディレクトリ構造

【ルートディレクトリ】
├─ .circleci
│   └─ config.yml
├─ aws / CloudFormation
│   └─ ec2.yml
├─ docker
│   └─ mysql
│   └─ nginx
│   └─ php
│   └─ phpmyadmin
├─ src
│   └─ 【Laravelのパッケージ】
│─ .env
│─ .gitignore
└─ docker-compose.yml

Reference

  • PHP・Laravelで検索機能を実装(備忘録) - Qiita

  • Laravel キーワード検索機能 - Qiita

  • Laravelで検索機能とページネーションを同時につけたいとき - Qiita

  • Laravelのページネーションが便利すぎた|Laravel|PHP|開発ブログ|株式会社Nextat(ネクスタット)

  • 【Laravel】all()の後にpaginateが使えない?原因と解決方法 | CODE CLUB965

  • Laravelで都道府県やカテゴリなどのプルダウンと文字入力から検索機能を実装する - Qiita

  • Laravelチュートリアル - 汎用業務Webアプリを作る (3/4) 検索画面とページネーション - Qiita

  • 【laravel】configフォルダを使用したプルダウンの作り方 - Qiita

  • Laravel(+Vue.js)でSNS風Webサービスを作ろう! | Techpit

  • Laravel × CircleCI × AWSで学ぶCI/CD | Techpit

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?