Category : #laravel
Tags : #laravel, #laravel search
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
After Search
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">
</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
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
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.