Implementation of repository pattern for CodeIgniter 4. The package allows out-of-the-box filtering of data based on parameters in the request, and also allows you to quickly integrate the list filters and custom criteria.
Via Composer
$ composer require agungsugiarto/codeigniter4-repository
https://example.com/news?title=Title&custom=value&orderBy=name_desc
It will automatically apply built-in constraints onto the query as well as any custom scopes and criteria you need:
protected $searchable = [
// where 'title' equals 'Title'
'title',
];
protected $scopes = [
// and custom parameter used in your scope
'custom' => MyScope::class,
];
class MyScope extends ScopeAbstract
{
public function scope($builder, $value, $scope)
{
return $builder->where($scope, $value)->orWhere(...);
}
}
Ordering by any field is available:
protected $scopes = [
// orderBy field
'orderBy' => OrderByScope::class,
];
Package can also apply any custom criteria:
return $this->news->withCriteria([
new MyCriteria([
'category_id' => '1',
'name' => 'Name',
['created_at', '>', Time::now()],
]),
...
])->get();
Create your model:
namespace App\Models;
use CodeIgniter\Model;
class News extends Model
{
...
}
Extend it from Fluent\Repository\Eloquent\BaseRepository
and provide entity()
method to return full model class name:
namespace App;
use App\Models\News;
use Fluent\Repository\Eloquent\BaseRepository;
class NewsRepository extends BaseRepository
{
public function entity()
{
// Whatever choose one your style.
return new News();
// or
return 'App\Models\News';
// or
return News::class;
}
}
use App\NewsRepository;
class NewsController extends BaseController
{
protected $news;
public function __construct()
{
$this->news = new NewsRepository();
}
....
}
- Execute the query as a "select" statement or get all results:
/**
* Get method implement parameter "select", "limit" and "offset".
* The default will be select * and return all offset data.
*
* Example: $this->news->get(['*'], 50, 100);
*/
$news = $this->news->get();
- Execute the query and get the first result:
$news = $this->news->first();
- Find a model by its primary key:
$news = $this->news->find(1);
- Add basic where clauses and execute the query:
$news = $this->news->findWhere([
// where id equals 1
'id' => '1',
// other "where" operations
['news_category_id', '<', '3'],
...
]);
- Paginate the given query:
Note:
"paginate": {}
avaliable methods see docs
$news = $this->news->paginate(15);
// return will be
{
"data": [
{
"id": "3",
"title": "Ms. Carole Wilderman DDS",
"content": "Labore id aperiam ut voluptatem eos natus.",
"created_at": "2020-08-05 17:07:16",
"updated_at": "2020-08-05 17:07:16",
"deleted_at": null
},
...
],
"paginate": {}
}
- Add an "order by" clause to the query:
$news = $this->news->orderBy('title', 'desc')->get();
- Save a new model and return the instance:
$news = $this->news->create($this->request->getVar());
- Save a batch new model and return instance:
$data = [
[
'title' => 'My title',
'name' => 'My Name',
'date' => 'My date'
],
[
'title' => 'Another title',
'name' => 'Another Name',
'date' => 'Another date'
]
];
$news = $this->news->createBatch($data);
- Update a record:
$this->news->update($this->request->getVar(), $id);
- Update a batch record:
$data = [
[
'title' => 'My title',
'name' => 'My Name',
'date' => 'My date'
],
[
'title' => 'Another title',
'name' => 'Another Name',
'date' => 'Another date'
]
];
$news = $this->news->updateBatch($data, 'title');
- Delete a record by id:
$this->news->destroy($id);
Criteria are a way to build up specific query conditions.
use Fluent\Repository\Contracts\CriterionInterface;
class MyCriteria implements CriterionInterface
{
protected $conditions;
public function __construct(array $conditions)
{
$this->conditions = $conditions;
}
public function apply($entity)
{
foreach ($this->conditions as $field => $value) {
$entity = $entity->where($field, $value);
}
return $entity;
}
}
Multiple Criteria can be applied:
use App\NewsRepository;
class NewsController extends BaseController
{
protected $news;
public function __construct()
{
$this->news = new NewsRepository();
}
public function index()
{
return $this->news->withCriteria([
new MyCriteria([
'category_id' => '1', 'name' => 'Name'
]),
new WhereAdmin(),
...
])->get();
}
}
In your repository define which fields can be used to scope your queries by setting $searchable
property.
protected $searchable = [
// where 'title' equals parameter value
'title',
// orWhere equals
'body' => 'or',
// where like
'author' => 'like',
// orWhere like
'email' => 'orLike',
];
Search by searchables:
public function index()
{
return $this->news->scope($this->request)->get();
}
https://example.com/news?title=Title&body=Text&author=&email=gmail
Also several serchables enabled by default:
protected $scopes = [
// orderBy field
'orderBy' => OrderByScope::class,
// where created_at date is after
'begin' => WhereDateGreaterScope::class,
// where created_at date is before
'end' => WhereDateLessScope::class,
];
$this->news->scope($this->request)->get();
Enable ordering for specific fields by adding $orderable
property to your model class:
public $orderable = ['email'];
https://example.com/news?orderBy=email_desc&begin=2019-01-24&end=2019-01-26
orderBy=email_desc
will order by email in descending order, orderBy=email
- in ascending
You can also build your own custom scopes. In your repository override scope()
method:
public function scope(IncomingRequest $request)
{
// apply build-in scopes
parent::scope($request);
// apply custom scopes
$this->entity = (new NewsScopes($request))->scope($this->entity);
return $this;
}
Create your scopes
class and extend ScopesAbstract
use Fluent\Repository\Scopes\ScopesAbstract;
class NewsScopes extends ScopesAbstract
{
protected $scopes = [
// here you can add field-scope mappings
'field' => MyScope::class,
];
}
Now you can build any scopes you need:
use Fluent\Repository\Scopes\ScopeAbstract;
class MyScope extends ScopeAbstract
{
public function scope($builder, $value, $scope)
{
return $builder->where($scope, $value);
}
}
Released under the MIT License, see LICENSE.