We can easily search or filter a single model data in Laravel. But it is a little bit difficult to search multiple models in one query. There are some ways to search models with relational data in Laravel 10 application. I will share one of them that how to search multiple model data which means relational data in the Laravel 10 application. To create this relational model search in Laravel 10, I will use "spatielaravel searchable" package.

I will create a Product and Category model and create a relationship with the product and category. Then we will search for product and category in a single query. So you will learn how to search in multiple models in Laravel?

This "spatielaravel searchable" package is a great package to search multiple model. Let's see laravel search query with relationship. See the demo of this tutorial from below pic:

Before Search

laravel-10-multiple-model-search

After Search

laravel-10-search-relational-model

Step 1: Download Fresh Laravel 10

In the first step of spatielaravel searchable in Laravel, download a fresh Laravel application by the following command:

composer create-project laravel/laravel example-app

 

Step 2: Create Migration

In this step, we need to create a migration and model for generating a products and categories table. So run the below command:

php artisan make:model Product -m
php artisan make:model Category -m

 

Now update the migration like below:

database/migrations

<?php

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

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

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

 

And migrations for products table:

<?php

use App\Models\Category;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

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

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

 

And now update the model like along with the protected property guard to avoid mass assignment error and implements a Searchable interface to search data like below:

app/Models/Product.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Searchable\Searchable;
use Spatie\Searchable\SearchResult;

class Product extends Model implements Searchable
{
    use HasFactory;

    protected $guarded = [];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function getSearchResult(): SearchResult
    {
        $url = 'define your route here';

        return new SearchResult(
            $this,
            $this->name,
            $url
        );
    }
}

 

Now update the category model like:

app/Models/Category.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Searchable\Searchable;
use Spatie\Searchable\SearchResult;

class Category extends Model implements Searchable
{
    use HasFactory;

    protected $guarded = [];

    public function getSearchResult(): SearchResult
    {
        $url = 'define your route here';

        return new SearchResult(
            $this,
            $this->name,
            $url
        );
    }
}

 

Step 3: Generate Seeder

We need dummy data for the product and category table. So create a seeder like:

php artisan make:seeder ProductSeeder
php artisan make:seeder CategorySeeder

 

Now update the product seeder like:

Database\Seeders\ProductSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Category;
use App\Models\Product;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class ProductSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        for ($i = 0; $i < 20; $i++) {
            Product::create([
                'category_id' => random_int(1, 9),
                'name'        => fake()->paragraph()
            ]);
        }
    }
}

 

Now update the category seeder like:

Database\Seeders\CategorySeeder.php

<?php

namespace Database\Seeders;

use App\Models\Category;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class CategorySeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        for ($i = 0; $i < 10; $i++) {
            Category::create([
                'name' => fake()->name()
            ]);
        }
    }
}

 

Now update the database seeder file like:

Database\Seeders\DatabaseSeeder.php

<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use App\Models\Employee;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call(ProductSeeder::class);
        $this->call(CategorySeeder::class);
    }
}

 

Step 4: Connect database

In this step, we will connect the database, and I am going to use MySQL. So connect it like the below by updating the .env file:

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tutorial
DB_USERNAME=root
DB_PASSWORD=

 

Now run the migration command:

php artisan migrate

//and

php artisan db:seed

 

Read also: Laravel 10 Algolia Full Text Search Tutorial

 

Step 5:  Install Package

Now in this step, we need to install spatie/laravel-searchable package. So run the below command:

composer require spatie/laravel-searchable

 

Step 6:  Create Route

Now in this, I will use two route for laravel search related models you can create two routes for that. 

routes/web.php

<?php

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SearchController;

Route::get('product', [SearchController::class, 'index'])
    ->name('product.search');
Route::post('product', [SearchController::class, 'search']);

 

Step 7: Create Controller

Now in this step, we have to create an SearchController to define this index method for laravel advanced search.

php artisan make:controller SearchController

 

Now update the controller like:

app/Http/Controllers/SearchCountroller.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use App\Models\Category;
use Illuminate\Http\Request;
use Spatie\Searchable\Search;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Builder;

class SearchController extends Controller
{
    public function index(Request $request)
    {
        $products = Product::orderBy('id', 'desc')
            ->with('category')
            ->paginate(5);

        return view('product.index', compact('products'));
    }

    public function search(Request $request)
    {
        $searchResults = (new Search())
            ->registerModel(Product::class, 'name')
            ->registerModel(Category::class, 'name')
            ->perform($request->input('q'));

        return view('product.index', compact('searchResults','request'));
    }
}

 

Step 8: Create Views

We are almost there. Just we have to create our list file with all the product lists with the search form.

  • index.balde.php
  • app.blade.php

So create these files inside the following path and update them like below:

resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body style="background: #ddd;">
    <div id="app">
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse" aria-expanded="false">
                        <span class="sr-only">Toggle Navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="{{ url('/employee') }}" style="margin-left:190px;">Laravelia</a>
                </div>
                <div class="collapse navbar-collapse" id="app-navbar-collapse">
                    <ul class="nav navbar-nav">
                        &nbsp;
                    </ul>
                        <ul class="nav navbar-nav navbar-right" style="margin-right:190px;">
                        @guest
                            <li><a href="{{ route('login') }}">Login</a></li>
                            <li><a href="{{ route('register') }}">Register</a></li>
                        @else
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true">
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>
        
                                <ul class="dropdown-menu">
                                    <li>
                                        <a href="{{ route('account.index') }}">Account</a>
                                    </li>
                                    <li>
                                        <a href="{{ route('logout') }}"
                                            onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                            Logout
                                        </a>
        
                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
                                        </form>
                                    </li>
                                </ul>
                            </li>
                        @endguest
                    </ul>
                </div>
            </div>
        </nav>        
        <div class="container">
            <div class="col-md-2"></div>
            <div class="col-md-8">
                @yield('content')
            </div>
            <div class="col-md-2"></div>
        </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</body>
</html>

 

This page for showing all the product lists.

resources/views/product/index.blade.php

@extends('layouts.app')

@section('content')
    @if (session()->has('success'))
        <div class="alert alert-success">
            {{ session()->get('success') }}
        </div>
    @endif
    <div class="panel panel-default">
        <div class="panel-body">
            
            <form action="{{ route('product.search') }}" method="post">
                @csrf
                 <div class="row">
                    <div class="col-md-10 form-group">
                        <label for="">Search</label>
                        <input type="text" name="q" class="form-control" value="{{ isset($request) ? $request->q : '' }}" placeholder="Search product">
                     </div>
                     <div class="col-md-2 form-group" style="margin-top:25px;">
                        <input type="submit" class="btn btn-primary" value="Search">
                     </div>
                 </div>
            </form>
           
            @if (request()->has('q'))
                <h3 class="panel-heading">{{ $searchResults->count() }} results found for <b style="color:blue">{{ request('q') }}</b></h3>
                    <div class="pnael-body">
                        @foreach($searchResults->groupByType() as $type => $modelSearchResults)
                        <h2>{{ ucfirst($type) }}</h2>

                        @foreach($searchResults as $searchResult)
                            <ul>
                                <li><a href="{{ $searchResult->url }}">{{ $searchResult->title }}</a></li>
                            </ul>
                        @endforeach
                    @endforeach
                </div>
            @endif
            @if (!request()->has('q'))
            <strong>Product List</strong>
            <table class="table table-responsive table-bordered table-stripped" style="margin-top:10px;">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Name</th>
                        <th>Category</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach ($products as $product)
                    <tr>
                        <td>{{ $product->id }}</td>
                        <td>{{ $product->name }}</td>
                        <td>{{ $product->category->name }}</td>
                    </tr>
                    @endforeach
                </tbody>
            </table>
            {{ $products->links() }}
            @endif
        </div>
    </div>
@endsection

 

Read also: Laravel 10 Search Or Filter Data With Date Range

 

Now all are set to go. Now run php artisan serve command to start the development server and visit the following URL to check laravel search query with relationship.

URL
http://localhost:8000/product

 

Conclusion

Now we know how to use spatielaravel searchable package and how to search multiple model data in laravel 10 using spatielaravel searchable. Hope this How to search in multiple models in Laravel tutorial will help you.

Category : #laravel

Tags : #laravel , #laravel search