Reputation: 1964
I have seen quite a few articles on fulltext search in Laravel where users recommend using whereRaw(...) or DB::query(...), but my aim is to remain database agnostic. I understand that a where('col', 'like', '%foo%') is terrible w.r.t. performance.
So I believe I am left with creating my own database index. Is there something that I can do out of the box with Laravel, or some table structure that I can set up to build a faster search mechanism?
Currently, I have a 'main' table with a text column 'data' on which I am planning to run a search on. That is the only column on which I'm doing lookups.
Upvotes: 1
Views: 6536
Reputation: 6240
if queries are not a problem, this is how I did it.
First, include the search form in your view:
{{ Form::open(['method' => 'get']) }}
{{ Form::text('q',Input::get('q')) }}
{{ Form::submit('Search') }}
{{ Form::close() }}
Make sure the table you want to search is MyISAM, you can do this by adding this to a migration:
$table->engine = 'MYISAM';
After that, add this scope to your model and change the columns you want to search:
public function scopeSearch($query,$q) {
return empty($q) ? $query : $query->whereRaw(
"MATCH(title,contents,anotherfield)
AGAINST(? IN BOOLEAN MODE)",[$q]);
}
In your controller, just add the scope when fetching the data:
$posts = Posts::search(Input::get('q'))->get();
And it should work. In case you need to add pagination, do something like this:
$posts = Posts::search(Input::get('q'))->paginate(30);
And for showing the links in the view, use this code:
{{ $posts->appends(Input::except('page'))->links() }}
This will preserve all the GET params (including the query param) while paginating.
Upvotes: 5
Reputation: 832
This has been removed from Laravel 4 but as I already said in another question, it can easily be re-implemented as described here: http://creative-punch.net/implementing-laravel-4-full-text-search/
Though the FULLTEXT index does not work everywhere
Upvotes: 1
Reputation: 992
Here is a function i use for a simple full-text serach with laravel. If you use mysql rememeber to set the engine to MyISAM on the table.
I have this function in the model file so that i can call User::serachFilter('query'); from the controller.
public static function searchFilter($data, $pageLimit = '5')
{
$keyword = !is_array($data) ? array('+'.$data.'*') : $data;
$matchArray = array('firstName', 'lastName', 'location', 'address');
$columns = array();
foreach($matchArray as $column)
{
$columns[] = $column;
}
$match = implode(',', $columns);
$result = self::whereRaw('MATCH('.$match.') AGAINST (? IN BOOLEAN MODE)', $keyword)
->paginate($pageLimit);
return $result;
}
Edit: Since you diden't want to use whereRaw, test
$query = Input::get('search');
$pageLimit = Input::get('page_limit');
$search = DB::select("
select *
from users
where match(id, name, email, username)
against('+{$query}*' IN BOOLEAN MODE)
limit {$pageLimit}
");
return $search;
Upvotes: 1