Installation
composer require titasgailius/nova-search-relations
Publish the config file (if needed):
php artisan vendor:publish --provider="TitasGailius\NovaSearchRelations\NovaSearchRelationsServiceProvider"
Basic Usage
Add the HasSearchableRelations trait to your Nova resource:
use TitasGailius\NovaSearchRelations\Traits\HasSearchableRelations;
class Post extends Resource
{
use HasSearchableRelations;
// ...
}
First Use Case Define a searchable relation in your resource:
public static $searchableRelations = [
'author', // Searches the 'author' relation (e.g., User)
'tags', // Searches the 'tags' relation (e.g., Tag)
];
Nova will now allow searching related models directly from the index view.
Searching Related Models
author.name contains "John".Customizing Search Fields
Override the searchableRelationFields method to specify which fields to search:
public function searchableRelationFields($relationName)
{
return match($relationName) {
'author' => ['name', 'email'],
'tags' => ['name', 'slug'],
default => [],
};
}
Dynamic Relations Handle polymorphic or dynamic relations by extending the trait:
public function resolveSearchableRelation($relationName, $query)
{
if ($relationName === 'comments') {
return $query->whereHas('comments', fn($q) => $q->where('content', 'like', '%' . $this->search . '%'));
}
}
Integration with Nova Actions Combine with Nova actions for bulk operations:
public function fields(Request $request)
{
return array_merge(parent::fields($request), [
(new Text)->onlyOnDetail(),
(new HasSearchableRelations)->onlyOnIndex(),
]);
}
Eager Loading
Optimize queries by eager-loading relations in the resolveForNavigation method:
public static function resolveForNavigation($resource)
{
return $resource->load('author', 'tags');
}
Performance Issues
Schema::table('posts', function (Blueprint $table) {
$table->index('author_id');
});
Case Sensitivity
strtolower in custom queries:
$query->whereRaw('LOWER(name) LIKE LOWER(?)', ['%' . $this->search . '%']);
Circular Dependencies
posts and comments) may cause infinite loops. Explicitly define one direction:
public static $searchableRelations = ['posts']; // Only search posts, not comments
Nova Caching
php artisan nova:cache-clear
Debugging Queries Enable Laravel query logging to inspect generated SQL:
DB::enableQueryLog();
// Run Nova request
$queries = DB::getQueryLog();
Customizing the Search UI
Override the search blade template in resources/views/vendor/nova/search-relations/.
Example:
// app/Providers/NovaServiceProvider.php
public function tools()
{
return [
new \TitasGailius\NovaSearchRelations\NovaSearchRelations(),
];
}
Testing Use Nova’s HTTP tests to verify search functionality:
$this->actingAs($user)
->get('/nova/resources/posts?search=John')
->assertSee('John');
Extending Functionality Add support for soft-deleted relations by modifying the trait:
public function scopeSearchableRelation($query, $relationName, $search)
{
return $query->whereHas($relationName, fn($q) => $q->where('name', 'like', '%' . $search . '%')->withTrashed());
}
Documentation Gaps
posts.tags.category).How can I help you explore Laravel packages today?