Giter VIP home page Giter VIP logo

searchable's Introduction

Laravel Searchable

Laravel trait to add a search method for Eloquent which performs prioritized searches in a model.

Installation

$ composer require "jabbtech/searchable": "^3.0"

Configuration

Import the SearchableTrait class and add a $searchable property to your model to specify the columns to make searchable and their priority in search results. Columns with higher values are more important:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Jabbtech\Searchable\SearchableTrait;

class User extends Model
{

    use SearchableTrait;

    protected $searchable = [
        'columns' => [
            'users.first_name' => 10,
            'users.last_name' => 10,
            'users.bio' => 2,
            'users.email' => 5,
            'posts.title' => 2,
            'posts.body' => 1,
        ],
        'joins' => [
            'posts' => ['users.id','posts.user_id'],
        ],
    ];

    public function posts()
    {
        return $this->hasMany('App\Post');
    }

}

Basic Usage

Using the search method on a query builder instance builds a query that searches through your model using Laravel's Eloquent. The most basic call to search requires a single argument, a search string.

$users = User::search($query)->get();

The search method should be compatible with any eloquent method (with exceptions for SQL Server):

$users = User::search($query)->with('posts')->get();

$users = User::search($query)->with('posts')->paginate(20);

$users = User::search($query)->where('status', 'active')->take(10)->get();

Accepted Relevance Threshold

The second argument changes is an integer that can change the default threshold for accepted relevance. By default, the threshold for accepted relevance is the sum of all attribute relevance divided by 4.

Returning all users matching the search in order of relevance:

$users = User::search($query, 0)->get();

Prioritize Full Text Search

The third argument is a boolean which prioritizes matches that include the multi-word search. By default, multi-word search terms are split and Searchable searches for each word individually. Relevance plays a role in prioritizing matches that matched on multiple words.

Prioritizing matches containing "John Doe" above matches containing only "John" or "Doe":

$users = User::search("John Doe", null, true)->get();

Full Text Matches Only

The fourth argument is a boolean which allows searching for full text mathces only.

Excluding matches that only matched "John" OR "Doe".

$users = User::search("John Doe", null, true, true)->get();

SQL Server

When used with SQL Server the search method supports most eloquent methods with some limitations.

  • It is strongly recommended (and required in some cases) that the select method is used
    • Column constraints of tables you will join to need to be included in the select method
    • Column required by the where method need to be included in the select method
  • Most methods need to be used before the search method
    • join
    • leftJoin
    • crossJoin
    • where
  • Include orderBy('relevance', 'desc') after the search method
$users = User::select('first_name', 'last_name')
    ->search($query)
    ->orderBy('relevance', 'desc')
    ->get();

$users = User::select(
        'users.id',
        'users.first_name',
        'users.last_name',
        'users.bio',
        'users.email',
        'users.status',
        'posts.title',
        'posts.body'
    )->leftJoin('posts', 'users.id', 'posts.user_id')
    ->where('users.status', 'active')
    ->serch($query)
    ->orderBy('relevance', 'desc')
    ->get();

How does it work?

Searchable builds a query that searches through your model using Laravel's Eloquent. Here is an example query

Model

protected $searchable = [
    'columns' => [
        'first_name' => 10,
        'last_name' => 5
    ],
];

Search

$search = User::search('John Doe', null, true)->get();

Result

select * from (
    select `users`.*, max(
        (case when LOWER(`users`.`first_name`) LIKE 'John' then 150 else 0 end) + -- column equals word: priority * 15
        (case when LOWER(`users`.`first_name`) LIKE 'Doe' then 150 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE 'John%' then 50 else 0 end) + -- column starts with word: priority * 5
        (case when LOWER(`users`.`first_name`) LIKE 'Doe%' then 50 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE '%John%' then 10 else 0 end) + -- column contains word: priority * 1
        (case when LOWER(`users`.`first_name`) LIKE '%Doe%' then 10 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE 'John Doe' then 500 else 0 end) + -- column matches full text: priority * 50
        (case when LOWER(`users`.`first_name`) LIKE '%John Doe%' then 300 else 0 end) + -- column contains full text: priority * 30
        (case when LOWER(`users`.`last_name`) LIKE 'John' then 75 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'Doe' then 75 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'John%' then 25 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'Doe%' then 25 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%John%' then 5 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%Doe%' then 5 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'John Doe' then 250 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%John Doe%' then 150 else 0 end)
    ) as relevance 
    from `users` 
    group by `users`.`id` 
    having relevance >= 3.75 -- sum of priorities (10 + 5) / 4
    order by `relevance` desc
) as `users`

Credits

Contributing

Anyone is welcome to contribute. Fork, make your changes, and then submit a pull request.

searchable's People

Contributors

billmn avatar changeweb avatar curtisweeks avatar doncadavona avatar edilton avatar evertt avatar gnanakeethan avatar gufoe avatar iget-esoares avatar iget-master avatar jarnovanleeuwen avatar jonjrodriguez avatar joostbaptist avatar julientant avatar kerwitz avatar kordero avatar manavo avatar mangtomas23 avatar mitchellmckenna avatar n1crack avatar nicolaslopezj avatar omarmakled avatar osugregor avatar rizqyhi avatar rjackson avatar stevenwadejr avatar svrnm avatar tomzx avatar wunc avatar zawilliams avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

zxc20033

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.