gretschduojet's avatar

Searching

Hello,

I have a question regarding searching a table. I would like to search a users table with the following fields: name, email, city, state, zip. Name, email and city need to be fuzzy searched, because there's a chance we don't know the full name or we may only have part of an email address. I have watched the search tutorial and can get it to work with a single field, but once I start adding fields it no longer works. Any help would be greatly appreciated.

Thank you.

0 likes
4 replies
michaeldyrynda's avatar

You'll need to use orWhere if you want to match on any of those fields, and where. If you want to match on all of them.

For name and email, you can use orWhere('name', 'LIKE', "%{$name}%") and likewise with email. The % signifies the wildcard characters on either side of the supplied input.

One on either side will match a name/email within another string, one only on the left will mean a string that ends with the input, and one on the right will mean a string that begins with one.

gretschduojet's avatar

Thank you for your reply. I gave it a shot:

$name = Request::get('name');
$email = Request::get('email');
$city = Request::get('city');

$users = User::orWhere('name', 'LIKE', "%{$name}%")
                        ->orWhere('email', 'LIKE', "%{$email}%")
                        ->orWhere('city', 'LIKE', "%{$city}%")
                        ->get();

However, it seems to have a problem when one of the fields is empty. I'm not sure how to build the query and check if one of the values is empty. I returned the last query and for anyone that was empty it searched for '%%' - I was thinking that I could check if the value was equal to '%%', then I could just set it to empty. Thank you again for the help.

michaeldyrynda's avatar
Level 41

An empty variable will run a query that looks something like this:

SELECT * FROM `users` WHERE `name` = "%%" OR `email` LIKE "%me@example.com%" OR `city` LIKE "%adelaide%"

This becomes a problem because your wildcard is searching for a name (or email or city) that is anything.

What you could do is set yourself up a query scope in your user model:

class User extends Eloquent {

    // ...

    public function scopeFilter($query, $params)
    {
        if ( isset($params['name'] && trim($params['name']) !== '' )
        {
            $query->orWhere('name', 'LIKE', "%{$params['name']}%");
        }

        if ( isset($params['email'] && trim($params['email']) !== '' )
        {
            $query->orWhere('email', 'LIKE', "%{$params['email']}%");
        }

        if ( isset($params['city'] && trim($params['city']) !== '' )
        {
            $query->orWhere('city', 'LIKE', "%{$params['city']}%");
        }

        return $query;
    }

    // ...
}

Then in your controller / repository you can do something like:

$params = Input::only('name', 'email', 'city');
$users = Users::filter($params)->get();

>>> User::filter([ 'name' => 'testing', 'city' => 'adelaide', ])->get()->toArray();;
=> [
       [
           "id"         => "1",
           "name"       => "deringer",
           "email"      => "deringer@example.com",
           "created_at" => "2015-02-10 08:44:56",
           "updated_at" => "2015-02-10 08:44:56",
           "city"       => "Adelaide"
       ]
   ]

Using a scope means that you can reuse the filtering logic anywhere in the site, you can add additional filter parameters or tweak the behaviour of it in one place.

Let me know how you go.

1 like
gretschduojet's avatar

Thank you so much! That works perfectly and makes complete sense. Thank you again for your help.

1 like

Please or to participate in this conversation.