Muhammad Usman

Crazy tech lover, endless learner
Home

Filter Eloquent Results by Overriding in Laravel (v 3 & 4)

 
  Now Laravel has this feature [built-in](http://laravel.com/docs/4.2/eloquent#query-scopes)

What is Eloquent?

Eloquent has been a really popular ORM in the PHP community lately, it was initially built for Laravel framework only. But since Laravel 4 all the components including Eloquent are built as Packages which may depend on other packages. These packages can be installed through Composer and can be browsed on Packagist. So what’s cool? Think of people out there who either don’t use Laravel or don’t use any framework at all. They might roll their own code or just whack a bunch of packages (like Eloquent) from Packagist together. If you use Laravel you can install and use various Symfony components/packages or any other package like Hybrid Auth with a simple command.

Let’s Code

When we run queries from Eloquent sometimes we need to filter results from the very beginning. I will do it with an example to make understanding easy, but you are free to apply it however you want.

So sometimes we have users in database and admin can ban few of them for whatever reason, then lets assume you set users table’s status=0 for these users, now you have to filter (status=1) everywhere to restrict banned users from appearing (like login, profile view, edit send message etc.), and this can be real pain and not-a-cool-way as well. What if we can filter banned users right from our Eloquent model each time, so however we call users, User::all() or User::find(2) or User::where('username', 'like', '%usman%')->get() or whatever, banned users won’t appear in the results as long as you use this Eloquent model? Pretty cool yeah! Let’s do it:

You have a User model which extends Eloquent, put this code into that class:

   
/**  
* Overrides (Laravel or)Illuminate\Database\Eloquent\Model 's query()  
*  
* @return mixed  
*/  
public function newQuery($excludeDeleted = true)  
{  
    $query = parent::newQuery($excludeDeleted);  
    // A much better way to restrict access to all banned (status = 0) users  
    // from beginning (including search, profile views etc.), disabling them  
    // to access anything even if they were logged in previously.
    
    $query->where('status', '!=', 0);  
    return $query;  
}  

That’s pretty much it, now you will never see banned users 🙂

What if We Need to Get Banned Users?

Well, above code will basically serve the purpose, but what if we need to get banned users (too) sometimes, like in the admin panel or if we want to check why the login was denied, is it because his status=0? Well you can do it. After this feature, your overall class will look as follows:

   
class User extends Eloquent  
{  
    protected static $_allowBannedUsers = false;
    
    /**  
    * Overrides (Laravel or)Illuminate\Database\Eloquent\Model 's query()  
    *  
    * @return mixed  
    */  
    public function newQuery()  
    {  
        $query = parent::newQuery();  
        // A much better way to restrict access to all banned (status = 0) users  
        // from beginning (including search, profile views etc.), disabling them  
        // to access anything even if they were logged in previously.
        
        if(! static::$_allowBannedUsers)  
        {  
            $query->where('status', '!=', 0);  
            } else {  
            // If its true then make it false so that banned users don't appear in next calls.  
            static::$_allowBannedUsers = false;  
        }  
        return $query;  
    }

    /**  
    * @return User  
    */  
    public static function allowBannedUsers()  
    {  
        static::$_allowBannedUsers = true;  
        return new static;  
    }  
}  

The above code seems self explanatory. Now you can get banned users if needed just by chaining allowBannedUsers() method, for example:
User::allowBannedUsers()->all() or User::allowBannedUsers()->find(2) or User::allowBannedUsers()->where('username', 'like', '%usman%')->get()

Laravel 3?

If you are using Laravel 3 then please change the name of the method newQuery() to query() (without any parameters) like:

 public function query()

and

 
$query = parent::query();

If you like this trick then you may like my new project Pixie Database Query Builder. It has Query Events built-in for doing such tricks.

Conclusion

Feel free to do whatever you need instead of just restricting banned users. Also I would like to hear any better solution or if you think this solution has any pitfall. How do you solve this problem? Please comment below.

I will be glad if this helps you, please share this tutorial if you think it would help others.

Stay tuned for more Laravel tutorials.