, (*1)
If you're looking for a version which works with Laravel 4.x.x and 5.0.x, click here., (*2)
ScopeApplicator brings an elegant way of sorting and filtering data to your Laravel projects., (*3)
Overview
ScopeApplicator is an easy and logical way to achieve something like this:, (*4)
/posts – returns a list of all posts, (*5)
/posts?recent – returns only recent posts, (*6)
/posts?author_id=5 – returns posts belonging to an author with an id=5, (*7)
/posts?author_id=5&order_by_title=desc&status=active – returns only active posts belonging to an author with an id=5 and sorts them by a title in a descending order, (*8)
Requirements
Laravel ~5.1, (*9)
Installation
composer require mobileka/scope-applicator-laravel 1.1.*, (*10)
Usage (with Models)
Make sure you are familiar with Laravel's query scopes before you dive in, (*11)
Let's learn by example. First of all, we'll implement an author_id filter for posts table., (*12)
Please note that this is going to be a basic example and it's not the most optimal way of doing things ;), (*13)
These are steps required to achieve this:, (*14)
- Create a basic
PostController which outputs a list of posts when you hit /posts route
- Create a
userId scope in the Post model (and it has to extend the Mobileka\ScopeApplicator\Laravel\Model class)
- Tell ScopeApplicator that this scope is available and give it an alias
- Visit
/posts?author_id=1 and enjoy the result
Ok, let's cover these step by step., (*15)
— The PostController:, (*16)
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
return Post::all();
}
}
— The Post model:, (*17)
<?php namespace App\Models;
use Mobileka\ScopeApplicator\Laravel\Model;
class Post extends Model
{
public function scopeUserId($builder, $param = 0)
{
if (!$param) {
return $builder;
}
return $builder->where('user_id', '=', $param);
}
}
Note that it extends Mobileka\ScopeApplicator\Laravel\Model, (*18)
— Now we have to replace Post::all() in our controller with Post::handleScopes() and tell this mehotd which scopes are available for filtering:, (*19)
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Models\Post;
class PostController extends Controller
{
// an array of available scopes
public $scopes = [
'userId'
];
public function index()
{
return Post::handleScopes($this->scopes)->get();
}
}
Take a note that 'userId' matches the name of the scope we've created in the Post model (scopeUserId)., (*20)
At this moment you can add some dummy data to your posts table and make sure that you can filter it by hitting the following route:
/posts?userId=your_number, (*21)
But, as we wanted author_id instead of userId, let's create an alias for this scope:, (*22)
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Models\Post;
class PostController extends Controller
{
// an array of available scopes
public $scopes = [
'userId' => [
// Here it is!
'alias' => 'author_id'
]
];
public function index()
{
return Post::handleScopes($this->scopes)->get();
}
}
— That's it! Now you can visit /posts?author_id=x and check the result., (*23)
alias is only one of the many available scope configuration options. These are described in ScopeApplicator's documentation., (*24)
A better usage scenario (with Repositories)
ScopeApplicator can also be used with Repositories. It was actually designed to be used this way., (*25)
To achieve this, your repository has to extend the Mobileka\ScopeApplicator\Laravel\Repository class., (*26)
The ScopeApplicator is already attached to this class, so you'll have a new applyScopes() method available in repositories extending it., (*27)
Let's see an example BaseRepository before we extend the aforementioned class:, (*28)
<?php namespace Acme\Repositories;
class BaseRepository
{
protected $dataProvider;
public function __construct($dataProvider)
{
$this->dataProvider = $dataProvider;
}
public function getDataProvider()
{
return $this->dataProvider;
}
public function all()
{
return $this->getDataProvider()->all();
}
}
DataProvider is typically an instance of a Model., (*29)
And now what it looks like with ScopeApplicator:, (*30)
<?php namespace Acme\Repositories;
use Mobileka\ScopeApplicator\Laravel\Repository;
class BaseRepository extends Repository
{
protected $dataProvider;
public function __construct($dataProvider)
{
$this->dataProvider = $dataProvider;
}
public function getDataProvider()
{
return $this->dataProvider;
}
public function all($scopes = [])
{
// This part has to be noticed!
return $this->applyScopes($this->getDataProvider(), $scopes)->get();
}
}
Pay closer attention to all method. Now it accepts an array of scopes (the same array we were passing to Model::handleScopes())., (*31)
Instead of directly calling all on our DataProvider, we now use applyScopes() method which accepts a DataProvider instance as a first argument and a scope configuration array as a second., (*32)
Contributing
If you have noticed a bug or have suggestions, you can always create an issue or a pull request (use PSR-2). We will discuss the problem or a suggestion and plan the implementation together., (*33)
License
ScopeApplicator is an open-source software and licensed under the MIT License., (*34)