<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
inerba / filament-natural-language-filter example snippets
use Inerba\FilamentNaturalLanguageFilter\Filters\NaturalLanguageFilter;
public function table(Table $table): Table
{
return $table
->columns([
// your columns
])
->filters([
NaturalLanguageFilter::make()
->availableColumns([
'id',
'name',
'email',
'status',
'created_at',
'updated_at'
])
->availableRelations([
'orders',
'posts',
'profile'
])
]);
}
// Enable relationship filtering
NaturalLanguageFilter::make()
->availableColumns(['name', 'email'])
->availableRelations(['orders', 'posts'])
// Now supports: "users with orders over $100"
// "posts by active users"
// "products in electronics category"
// Enable boolean logic (AND/OR operations)
// Supports: "users named john OR email contains gmail"
// "active users AND created after 2023"
// "status is pending AND (amount > 100 OR priority is high)"
// Enable aggregation operations
// Supports: "top 10 users by order count"
// "products with highest sales"
// "users with most posts"
// ProductResource.php
use Inerba\FilamentNaturalLanguageFilter\Filters\NaturalLanguageFilter;
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name'),
TextColumn::make('category.name'),
TextColumn::make('price'),
TextColumn::make('stock_quantity'),
TextColumn::make('status'),
TextColumn::make('created_at'),
])
->filters([
NaturalLanguageFilter::make()
->availableColumns([
'name', 'price', 'stock_quantity', 'status',
'created_at', 'updated_at'
])
->availableRelations(['category', 'reviews', 'orders'])
->liveSearch()
]);
}
// Now supports queries like:
// - "products in electronics category"
// - "out of stock products"
// - "products with price over $100"
// - "products with more than 10 reviews"
// - "best selling products this month"
// UserResource.php
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name'),
TextColumn::make('email'),
TextColumn::make('status'),
TextColumn::make('created_at'),
TextColumn::make('last_login_at'),
])
->filters([
NaturalLanguageFilter::make()
->availableColumns([
'name', 'email', 'status', 'role',
'created_at', 'last_login_at', 'email_verified_at'
])
->availableRelations(['orders', 'posts', 'profile', 'subscriptions'])
->submitSearch()
]);
}
// Supports queries like:
// - "active users with gmail email"
// - "users who haven't logged in this month"
// - "premium subscribers with orders over $500"
// - "users created this week AND verified"
// PostResource.php
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title'),
TextColumn::make('author.name'),
TextColumn::make('status'),
TextColumn::make('published_at'),
TextColumn::make('views_count'),
])
->filters([
NaturalLanguageFilter::make()
->availableColumns([
'title', 'content', 'status', 'views_count',
'created_at', 'published_at'
])
->availableRelations(['author', 'comments', 'tags', 'category'])
->liveSearch()
]);
}
// Supports queries like:
// - "published posts by john"
// - "posts with more than 100 views"
// - "draft posts created this week"
// - "posts with comments from verified users"
// OrderResource.php
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('order_number'),
TextColumn::make('customer.name'),
TextColumn::make('status'),
TextColumn::make('total_amount'),
TextColumn::make('created_at'),
])
->filters([
NaturalLanguageFilter::make()
->availableColumns([
'order_number', 'status', 'total_amount',
'created_at', 'shipped_at', 'delivered_at'
])
->availableRelations(['customer', 'items', 'shipping_address'])
->submitSearch()
]);
}
// Supports queries like:
// - "orders over $1000"
// - "pending orders from premium customers"
// - "orders shipped this week"
// - "orders with more than 5 items"
// For large datasets, use submit mode
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->submitSearch() // Reduces API calls
->availableRelations(['orders']) // Limit relationships
// The filter automatically detects and handles multiple languages
// No additional configuration needed!
// English: "active users"
// Spanish: "usuarios activos"
// French: "utilisateurs actifs"
// German: "aktive benutzer"
// Arabic: "المستخدمون النشطون"
// Extend the filter for custom behavior
class CustomNaturalLanguageFilter extends NaturalLanguageFilter
{
protected function applyFilter(Builder $query, array $filter): void
{
// Add custom logic before applying filter
if ($filter['column'] === 'status' && $filter['value'] === 'active') {
// Custom logic for active status
$query->where('status', 'active')
->where('email_verified_at', '!=', null);
return;
}
// Apply standard filter
parent::applyFilter($query, $filter);
}
}
public function table(Table $table): Table
{
return $table
->filters([
// Combine with other Filament filters
SelectFilter::make('status')
->options([
'active' => 'Active',
'inactive' => 'Inactive',
]),
DateFilter::make('created_at'),
// Natural language filter works alongside others
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->liveSearch()
]);
}
// Use in API endpoints
class UserController extends Controller
{
public function index(Request $request)
{
$query = User::query();
if ($request->has('natural_query')) {
$filter = NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->availableRelations(['orders']);
$query = $filter->apply($query, [
'query' => $request->get('natural_query')
]);
}
return $query->paginate();
}
}
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->submitSearch() // Users press Enter to search
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->liveSearch() // Search happens automatically as user types
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->searchMode('live') // or 'submit'
// Use submit mode instead of live mode
NaturalLanguageFilter::make()
->submitSearch() // Reduces API calls
// Limit available columns
->availableColumns(['name', 'email', 'status']) // Only essential columns
// Disable expensive features
FILAMENT_NL_FILTER_RELATIONSHIP_FILTERING=false
FILAMENT_NL_FILTER_AGGREGATION_QUERIES=false
// Add more context to available columns
->availableColumns([
'name', 'email', 'status', 'created_at',
'first_name', 'last_name', 'full_name' // Add variations
])
// Enable debug logging
FILAMENT_NL_FILTER_LOGGING=true
FILAMENT_NL_FILTER_LOG_LEVEL=debug
// Ensure relationships are properly defined
// In your model:
public function orders()
{
return $this->hasMany(Order::class);
}
// In the filter:
->availableRelations(['orders']) // Use exact relationship names
// Use eager loading for relationships
$users = User::with(['orders', 'profile'])
->where('status', 'active')
->get();
// Limit relationship depth
FILAMENT_NL_FILTER_MAX_RELATION_DEPTH=1
// Test in tinker
php artisan tinker
// Test OpenAI
$processor = app(\Inerba\FilamentNaturalLanguageFilter\Contracts\NaturalLanguageProcessorInterface::class);
$result = $processor->processQuery('active users', ['name', 'status']);
dd($result);
// Override system prompt in config
'custom_prompts' => [
'system' => 'You are a specialized database query assistant for e-commerce...',
'user' => 'Convert this e-commerce query: {query}',
],
// Add rate limiting for API calls
'rate_limiting' => [
'enabled' => true,
'max_requests_per_minute' => 60,
'max_requests_per_hour' => 1000,
],
// Before (basic)
NaturalLanguageFilter::make()
->availableColumns(['name', 'email'])
// After (advanced)
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status', 'created_at'])
->availableRelations(['orders', 'profile'])
->liveSearch()
// Good: Specific, relevant columns
->availableColumns(['name', 'email', 'status', 'created_at'])
// Avoid: Too many columns
->availableColumns(['*']) // Don't do this
// Good: Essential relationships only
->availableRelations(['orders', 'profile'])
// Avoid: Deep relationship chains
->availableRelations(['orders.items.product.category']) // Too deep
// Add performance monitoring
use Illuminate\Support\Facades\Log;
// Log slow queries
if ($query->getQuery()->time > 1000) {
Log::warning('Slow natural language query', [
'query' => $queryText,
'time' => $query->getQuery()->time
]);
}
// Test in tinker
php artisan tinker
// Test basic filtering
$filter = NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status']);
$result = $filter->apply(User::query(), ['query' => 'active users']);
dd($result->toSql());
// Test AI processor directly
$processor = app(\Inerba\FilamentNaturalLanguageFilter\Contracts\NaturalLanguageProcessorInterface::class);
// Test query processing
$filters = $processor->processQuery('users created after 2023', ['name', 'created_at']);
dd($filters);
// Test relationship queries
$filter = NaturalLanguageFilter::make()
->availableColumns(['name', 'email'])
->availableRelations(['orders']);
$result = $filter->apply(User::query(), ['query' => 'users with orders over $100']);
dd($result->toSql());
// Test in Filament resource
class UserResource extends Resource
{
public function table(Table $table): Table
{
return $table
->filters([
NaturalLanguageFilter::make()
->availableColumns(['name', 'email', 'status'])
->availableRelations(['orders'])
]);
}
}
// Test the actual Filament page
// Visit /admin/users and try natural language queries
// Test with large datasets
$startTime = microtime(true);
$users = User::with(['orders'])
->where('status', 'active')
->get();
$endTime = microtime(true);
$executionTime = ($endTime - $startTime) * 1000; // Convert to milliseconds
Log::info("Query execution time: {$executionTime}ms");
// Add your new feature code
// Follow existing patterns and add tests
// Create test file
tests/Feature/NewFeatureTest.php
// Write comprehensive tests
public function test_new_feature_works()
{
// Test implementation
}