Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Tucker-Eric committed Mar 4, 2016
0 parents commit 90cfd52
Show file tree
Hide file tree
Showing 10 changed files with 722 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
vendor
.idea
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) <Eric Tucker>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
261 changes: 261 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# Eloquent Filter
An Eloquent way to filter Eloquent Models

## Introduction
Lets say we want to return a list of users filtered by multiple parameters. When we navigate to:

`/users?name=er&last_name=&company_id=2&roles[]=1&roles[]=4&roles[]=7&industry=5`

`$request->all()` will return:
```php
[
'name' => 'er',
'last_name' => ''
'company_id' => '2',
'roles' => ['1','4','7'],
'industry' => '5'
]
```
To filter by all those parameters we would need to do something like:
```php
<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\User;

class UserController extends Controller
{

public function index(Request $request)
{
$query = User::where('company_id', $request->input('company_id'));

if ($request->input('last_name') !== '')
{
$query->where('last_name', 'LIKE', '%' . $request->input('last_name') . '%');
}

if ($request->input('name') !== '')
{
$query->where(function ($q) use ($request)
{
return $q->where('first_name', 'LIKE', $request->input('name') . '%')
->orWhere('last_name', 'LIKE', '%' . $request->input('name') . '%');
});
}

$query->whereHas('roles', function ($q) use ($request)
{
return $q->whereIn('id', $request->input('roles'));
})
->whereHas('clients', function ($q) use ($request)
{
return $q->whereHas('industry_id', $request->input('industry'));
});

return $query->get();
}

}
```
To filter that same input With Eloquent Filters:

```php
<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\User;

class UserController extends Controller
{

public function index(Request $request)
{
return User::filter($request->all())->get();
}

}
```

## Configuration
After installing the Eloquent Filter library, register the `EloquentFilter\ServiceProvider::class` in your `config/app.php` configuration file:
```php
'providers' => [
// Other service providers...

EloquentFilter\ServiceProvider::class,
],
```
Copy the package config to your local config with the publish command:
```bash
php artisan vendor:publish --provider="EloquentFilter\ServiceProvider"
```
In the `app/eloquentfilter.php` config file. Set the namespace your model filters will reside in:
```php
'namespace' => "App\\ModelFilters\\",
```

## Usage

### Generating The Filter
You can create a model filter with the following artisan command:
```bash
php artisan model:filter User
```
Where `User` is the Eloquent Model you are creating the filter for. This will create `app/ModelFilters/UserFilter.php`

### Defining The Filter Logic
Define the filter logic based on the camel cased input key passed to the `filter()` method.

- Empty strings are ignored
- `_id` is dropped from the end of the input to define the method so filtering `user_id` would use the `user()` method
- Input without a corresponding filter method are ignored
- The value of the key is injected into the method
- All values are accessible through the `$this->input()` method or a single value by key `$this->input($key)`
- All Eloquent Builder methods are accessible in `this` context in the model filter class.

### Applying The Filter To A Model

Implement the `EloquentFilter\Filterable` trait on any Eloquent model:
```php
<?php namespace App;

use EloqentFilter\Filterable;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use Filterable;

//User Class
}
```
This gives you access to the `filter()` method that accepts an array of input:
```php
class UserController extends Controller
{
public function index(Request $request)
{
return User::filter($request->all())->get();
}
}
```

#### Filtering By Relationships
In order to filter by a relationship (whether the relation is joined in the query or not) add the relation in the `$relations` array with the name of the relation as referred to on the model as the key and the column names that will be received as input to filter.

The related model **MUST** have a ModelFilter associated with it. We instantiate the related model's filter and use the column values from the `$relations` array to call the associated methods.

This is helpful when querying multiple columns on a relation's table. For a single column using a `$this->whereHas()` method in the model filter works just fine

##### Example:

If I have a `User` that `hasMany` `App\Client::class` my model would look like:
```php
class User extends Model
{
use Filterable;

public function clients()
{
return $this->hasMany(Client::class);
}
}
```
Let's also say each `App\Client` has belongs to `App\Industry::class`:
```php
class User extends Model
{
use Filterable;

public function industry()
{
return $this->belongsTo(Industry::class);
}
}
```
We want to query our User's and filter them based on the industry of their client:

Input used to filter:
```php
$input = [
industry => 5
];
```
`UserFilter` with the relation defined so it's able to be queried.
```php
class UserFilter extends ModelFilter
{
public $relations = [
'clients' => ['industry'],
];
}
```
`ClientFilter` with the `industry` method that's used to filter:
```php
class UserFilter extends ModelFilter
{
public $relations = [];

public function industry($id)
{
return $this->where('industry_id', $id);
}
}
```

If the following array is passed to the `filter()` method:
```php
[
'name' => 'er',
'last_name' => ''
'company_id' => 2,
'roles' => [1,4,7],
'industry' => 5
]
```
In `app/ModelFilters/UserFilter.php`:
```php
<?php namespace App\ModelFilters;

use EloquentFilter\ModelFilter;

class UserFilter extends ModelFilter
{
public $relations = [
'clients' => ['industry'],
];

public function name($name)
{
return $this->where(function($q)
{
return $q->where('first_name', 'LIKE', $name . '%')->orWhere('last_name', 'LIKE', '%' . $name.'%');
});
}

public function lastName($lastName)
{
return $this->where('last_name', 'LIKE', '%' . $lastName);
}

public function company($id)
{
return $this->where('company_id',$id);
}

public function roles($ids)
{
return $this->whereHas('roles', function($query) use ($ids)
{
return $query->whereIn('id', $ids);
});
}
}
```
# Contributing
Any contributions welcome!
26 changes: 26 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "tucker-eric/eloquentfilter",
"description": "An Eloquent way to filter Eloquent Models",
"keywords": [
"laravel",
"eloquent",
"filter"
],
"license": "MIT",
"authors": [
{
"name": "Eric Tucker",
"email": "[email protected]"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/database": "~5.0"
},
"autoload": {
"psr-4": {
"EloquentFilter\\": "src/"
}
},
"minimum-stability": "dev"
}
16 changes: 16 additions & 0 deletions config/eloquentfilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

return array(

/*
|--------------------------------------------------------------------------
| Eloquent Filter Settings
|--------------------------------------------------------------------------
|
| This is the namespace all you Eloquent Model Filters will reside
|
*/

'namespace' => "App\\ModelFilters\\",

);
13 changes: 13 additions & 0 deletions src/Filterable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php namespace EloquentFilter;

trait Filterable
{
protected $filter;

public function scopeFilter($query, array $input)
{
$filter = config('eloquentfilter.namespace').class_basename($this).'Filter';

return with(new $filter($query,$input))->handle();
}
}
Loading

0 comments on commit 90cfd52

Please sign in to comment.