dees040 / repository
A Laravel package for the repository pattern.
Requires
- illuminate/support: 5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*
- laravel/legacy-factories: ^1.0
Requires (Dev)
- mockery/mockery: ^1.1
- orchestra/testbench: 3.5.*|3.6.*|3.7.*|4.*|5.*|6.*
- phpunit/phpunit: 6.0.*|7.0.*|8.0.*|9.0.*
This package is auto-updated.
Last update: 2024-10-14 20:28:26 UTC
README
THIS PACKAGE IS A WORK IN PROGRESS
This packages helps you to easily implement the repository package in your Laravel application.
Why use this package out of the many other Laravel repository package? This package was inspired by multiple other Laravel repository package. I took all the good things from those packages and create one unique package for it. Also I keep maintain this package, because I use it in multiple of my own projects.
Installation
You can install this package using composer, by running the following command:
composer require dees040/repository
The service provider is automatically added via Laravel package discovery.
Methods
Dees040\Repository\Contracts\Repository
all($columns = ['*'])
paginate($perPage = null, $columns = ['*'])
first($columns = ['*'])
find($id, $columns = ['*'])
findOrFail($id, $columns = ['*'])
findByField($field, $value, $columns = ['*'])
findWhere(array $where, $columns = ['*'])
findWhereIn(array $where, $columns = ['*'])
firstOrCreate(array $attributes, array $values = [])
create(array $attributes = [])
insert(array $attributes = [])
update($id, array $attributes)
updateOrCreate(array $attributes, array $values = [])
delete($id)
deleteWhere(array $where)
deleteWhereIn(array $where)
orderBy($column, $direction = 'asc')
with($relations)
has($relation)
whereHas($relation, \Closure $closure)
orWhereHas($relation, \Closure $closure)
sync($id, $relation, $attributes, $detaching = true)
syncWithoutDetaching($id, $relation, $attributes)
Usage
Creating a repository
Repositories can be created by hand or via a command provided in this package. If you'd like to create a repository by hand you should create two files for each repository.
One class for the repository contract:
<?php namespace App\Repositories\Contracts; use Dees040\Repository\Contracts\Repository; interface PostRepository extends Repository { }
And one class for the actual repository:
<?php namespace App\Repositories; use App\Post; use App\Repositories\Contracts\PostRepository; use Dees040\Repository\Eloquent\BaseRepository; class PostEloquentRepository extends BaseRepository implements PostRepository { /** * Get the base model. * * @return string */ public function getModel() { return Post::class; } }
The other option is creating the file using the make:repository
command:
php artisan make:repository Post
Usage in controllers
After creating the repository you should bind the repository contract to the correct repository using the Laravel Container. By doing this Laravel knows exactly which repository to use for which contract. This makes it very easy to switch between a eloquent repository or e.g. a MongoDB repository.
So before using any repositories in your controller make sure to bind it to the container. You can do that using the bind($abstract, concrete)
method in the Container
. E.g.: App::bind(\App\Repositories\Contracts\PostRepository::class, \App\Repositories\PostEloquentRepository::class)
.
Personally I like to create a new service provider named \App\Providers\RepositoryServiceProvider.php
and do something like this:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class RepositoryServiceProvider extends ServiceProvider { /** * The contracts with their associated repositories. * * @var array */ protected $repositories = [ \App\Repositories\Contracts\PostRepository::class => \App\Repositories\PostEloquentRepository::class, ]; /** * Bootstrap services. * * @return void */ public function boot() { // } /** * Register services. * * @return void */ public function register() { foreach ($this->repositories as $contract => $repository) { $this->app->bind($contract, $repository); } } }
After binding in to the container you can use dependency injection inside your controller to get the repository.
public function __contruct(PostRepository $repostiroy) { $this->repository = $repostiroy; }
Using criteria
If you'd like to execute custom queries to the database call you can use criteria. You can add criteria to your call by calling the pushCriteria
method.
$this->repository->pushCriteria(new Criteria()); $this->repository->pushCriteria(Criteria::class);
Make sure that your custom criteria classes are implementing the \Dees040\Repository\Contracts\Criteria
interface. An example of custom criteria is:
<?php namespace App\Criteria; use Dees040\Repository\Contracts\Criteria; class HasUserRelationCriteria implements Criteria { /** * Execute the criteria. * * @param \Illuminate\Database\Eloquent\Model $model * @param \Dees040\Repository\Contracts\Repository $repository * @return \Illuminate\Database\Eloquent\Model */ public function apply($model, $repository) { return $this->model->orderBy('created_at') ->whereHas('users', function ($query) { $query->where('users.id', 1); }); } }
RequestCriteria
The package ships with a useful criteria out of the box. The RequestCriteria
. It gives you the ability to easily perform extra actions on your queries via the route parameters. You can add order by items or search through your models. You can add the criteria by default in the constructor of a repository:
public function __construct() { $this->pushCriteria(\Dees040\Repository\Criteria\RequestCriteria::class); }
After doing this you can add following query parameters.
https://example.test/posts?order_by=created_at
https://example.test/posts?order_by=created_at&sort_by=desc
https://example.test/posts?search=Lorem ipsum
https://example.test/posts?search=Lorem ipsum&search_fields=body
https://example.test/posts?search=Lorem ipsum&search_fields=title,body:like
https://example.test/posts?search=Lorem ipsum&search_fields=title,body:like&order_by=title
If you'd like to have the ability to search you should override the getSearchableFields()
method in your repository. All the fields returned in the array of that method are then searchable via the route parameters.
/** * Get all fields which are searchable. * * @return array */ public function getSearchableFields() { return [ 'title', 'body', ]; }
TODOS
- Create a build in criteria class for requests
- Search fields in the request criteria
- Create cache
- Parse results
- Pagination options
- Search on custom fields in request criteria
- Dynamic criteria class
- Regex split on search fields
- Add dot nation for relations in request criteria
- Create commands