Download the PHP package aaronjan/housekeeper without Composer
On this page you can find all versions of the php package aaronjan/housekeeper. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download aaronjan/housekeeper
More information about aaronjan/housekeeper
Files in aaronjan/housekeeper
Package housekeeper
Short Description Powerful, simple Repository-Pattern implementation for Laravel (>=5.1), and it come with tests.
License Apache-2.0
Informations about the package housekeeper
Housekeeper - Laravel
After nearly six months developing, testing and polishing, the first stable version of Housekeeper 2
is finally released!
Housekeeper
aims to be the coolest, handiest Repository Pattern
implementation, any useful suggestion and PR are welcomed.
Increasing unit test code coverage is a work in progress (lots of works), but there is a set of integration tests running locally that covered most code.
Introduction
Housekeeper
is a flexable and powerful Repository Pattern
implemention for Laravel
. In addition to the basic Repository Pattern
and elegant syntax, Housekeeper
has features like Injection system
, Auto-Booting Method that will let you creating endless possibilities. The goal of Housekeeper
is free you from the redundant and boring DAL
stuff, coding more intuitively.
Sections
- Repository Pattern and Housekeeper
- Installation
- TL;DR (Quick start)
- Features
- API
- Abilities
- Adjustable
- Eloquently
- CacheStatically
- Guardable
- SoftDeletes
- Issue
- Lisence
- Credits
Repository Pattern and Housekeeper
The Repository Pattern
is a software design pattern. In a nutshell, it means to encapsulate your data interaction code as methods that belong to different classes (Base on data domain), we call this type of class as Repository
. When your business logic layer needs to accessing data such as an article entry in the database, it should ask to the Article Repository
instead of writing inline query that deal with database directly.
OK, but ... I already got Eloquent, why not just using that?
Of course you can! But there're people who's not a fan of the Active Record, it just doesn't feel right for them, for these people, the Repository Pattern makes more sense. Besides, you can write method that is more expressive on your repository class, like getActivatedUsers(), and you can write tests for them very easily.
More importantly, Housekeeper
is a better version of Repository Pattern
(In some ways), you could read more about it below.
Housekeeper loves Eloquent. Most query APIs are the same as the Eloquent's, so you can use them without the needing to learn anything, and the returns are like Eloquent's too.
Installation
Requirement
PHP
>= 5.5
and Laravel
>= 5.1
Install Via Composer
or add these to your composer.json
file:
then execute console command:
After Composer
finish running, add the HousekeeperServiceProvider
to the providers in config/app.php
:
Make a configuration file for Housekeeper
could allow you to tweak things:
It's done! Now you can make a repository:
TL;DR
If you have outstanding insight, this section will tell you how to use Housekeeper
in the simplest words.
-
Do not write
class constructor
, useboot
method instead, supportsType-Hinting
. -
Any public method that name starts with boot and followed by an upper-case letter (for instance, bootForInject), then this method will be called during class initializing, also support
Type-Hinting
. -
If you want to do something before/after some methods belong across multiple repository, encapsulate these logics as
Injections
then inject them into your repositorys. - By using the two features above, you can write
Trait
to injectInjection
, and use it in your repository.
Take a example:
-
Housekeeper
has someAbilities
(traits) that are out-of-the-box:-
Adjustable
-
Eloquently
-
CacheStatically
-
Guardable
- SoftDeletes
-
- You have to write two methods for every method you meant to write (Recommended):
That's it, take a look at the Abilities
' code for more usages, Have fun!
Features
Extend-less & Flows
The Repository Pattern
is usually used with the Decorator Pattern
. For instance, you have a repository class to interacting with data source directly, later you decide to add cache logic on top of that, so instead of changing the repository class its self, you could create a new class that extending it, and the whole thing may looks like this:
The Repository class
is the bottom layer, CachedRepository class
is another layer that base on the former, so one layer just do one thing (SRP: Single Responsibility Principle).
That is a good approach. But Housekeeper
wants to solving the problem with less code by using Flows
.
Flows
are three stages in every method execution, they're: Before
, After
and Reset
. Every method in a Housekeeper Repository
should be wrapped so it can go through these Flows
. Here is an example:
Why there are two methods that had similar names? Well, the getByName
method is basically a configuration and an API hint for the core method _getByName
, it wrapped the core method by calling the simpleWrap
with an Callable
which is [$this, '_getByName']
, It says what this method does is reading
data (Action::READ
), the whole reading logic is in the _getByName
method.
You don't have to worry about method arguments, Housekeeper
will takes care of that. In fact, you don't even need to write [$this, '_getByName']
, since it's a convention in Housekeeper
(An underscore before your method name):
Let's back to the cache logic
topic. In Housekeeper
, if you wrapped your method like above, than to adding cache process, all you need to do is writing a single line of code like this:
Now all your method returns will be cached automatically, just like that.
Is it cool?
Injection & Booting
Here a sequence diagram of method execution in Housekeeper
(Core Flow is the actual method logic):
Housekeeper
allows you to inject logic (called Injection
) into any Flow
, in every Flow
, the Injections
that belong to the Flow
will be executed. Injection
is just like Middleware
but with 3 types: Before
, After
and Reset
(matching 3 different injectable Flows
). Here is an example:
The handle
method in Injection
takes a Flow
object, depends on what Flow
you injected into, the methods of the Flow
object could be different, for instance, Before Flow
provides setReturnValue
method, you could call it by pass a value to it, then Housekeeper
will use this value as the return and skip the actual method.
You can inject Injection
by using the these methods: injectIntoBefore
, injectIntoAfter
and injectIntoReset
.
Here is flowchart of the Before Flow
execution:
Housekeeper
also will calling every method in the Repository
class that name start with boot
(before calling the boot
method) when Repository
instance been creating, some of the out-of-the-box Abilities
in Housekeeper
are took advantage of this, like in Adjustable
trait:
Wrapping layer
Let's assume someone wrote code like these:
In this example, the applyWheres
method has been used twice, one is in the Controller
, the other is in the Repository
, could the first one affecting the _getArticlesByAuthorId
method? No. It will only affecting the _getArticlesBySameAuthor
method, and be more precisely, it's affecting this line:
Every wrapped method in Housekeeper
has their own Scope
, means they have their own Eloquent Model
(Or Builder
), thus they will not taking any affect to each other. If you calling applyWheres
or ApplyOrderBy
outside the repository, they would only affecting the first wrapped method you called.
Another Choice For Wrapping
Having two methods could be annoying, you can write an Anonymous Function
, before the simpleWrap
takes a Callable
:
API
whereAre(array $wheres)
Add an array of where clauses to the query.
Arguments
$wheres
- An array ofwhere
conditions.
Example
applyWheres(array $wheres)
Alias for the whereAre
method.
Arguments
$wheres
- An array ofwhere
conditions.
orderBy($column, $direction = 'asc')
Add an "order by" clause to the query.
Arguments
$column
$direction
Example
applyOrderBy($column, $direction = 'asc')
Alias for the orderBy
method.
Arguments
$column
$direction
offset($value)
Set the "offset" value of the query.
Arguments
$value
- The specified offset of the first row to return.
Example
limit($value)
Set the "limit" value of the query.
Arguments
$value
- The maximum number of rows to return.
Example
exists($id, $column = null)
Determine if the record exists using its primary key.
Arguments
$id
- The primary key of the record.$column
- You could also specify a column other than primary key, and change the value of$id
correspondingly.
Examples
You could use this method with custom query conditions too:
count($columns = '*')
Retrieve the "count" result of the query.
Arguments
$columns
find($id, $columns = array('*'))
Find a model by its primary key.
Arguments
$id
$columns
- Specify columns that you want to retrieve.
Examples
findMany($ids, $columns = array('*'))
Find a collection of models by their primary key.
Arguments
$ids
$columns
- Specify columns that you want to retrieve.
update($id, array $attributes)
Update a record in the database.
Arguments
$id
$attributes
Examples
create(array $attributes)
Create a model with $attributes
.
Arguments
$attributes
delete($id)
Delete a record from the database by its primary key.
Arguments
$id
first($columns = ['*'])
Execute the query and retrieve the first result.
Arguments
$columns
all($columns = ['*'])
Execute the query as a "select" statement.
Arguments
$columns
paginate($limit = null, $columns = ['*'], $pageName = 'page', $page = null)
Paginate the given query.
Arguments
$limit
$columns
$pageName
$page
getByField($field, $value = null, $columns = ['*'])
Retrieve models by a simple equality query.
Arguments
$field
$value
$columns
with($relations)
Set the relationships that should be eager loaded, like Eloquent
.
Examples
Adjustable
For more complex queries, you could put them in a Criteria
class that is more semantic and reuse them anywhere you want, for that, using the Adjustable
ability.
Examples
Then in your controller:
API
applyCriteria(\Housekeeper\Abilities\Adjustable\Contracts\Criteria $criteria)
Apply this Criteria
only once.
Arguments
$criteria
- Criteria object.
rememberCriteria(\Housekeeper\Abilities\Adjustable\Contracts\Criteria $criteria)
Remember this Criteria
, it will be applied when every wrapped method been called (Only the first one, iternal method calling will be ignored).
Arguments
$criteria
- Criteria object.
forgetCriterias()
Remove all remembered Criterias
(Not applied).
getCriterias()
Get all remembered Criterias
.
Eloquently
This Abilitiy
provides lots of Eloquent
style query APIs that you are very familiar with.
API
where($column, $operator = null, $value = null, $boolean = 'and')
orWhere($column, $operator = null, $value = null)
has($relation, $operator = '>=', $count = 1, $boolean = 'and', \Closure $callback = null)
whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
whereDoesntHave($relation, Closure $callback = null)
orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
whereIn($column, $values, $boolean = 'and', $not = false)
whereNotIn($column, $values, $boolean = 'and')
orWhereNotIn($column, $values)
whereNull($column, $boolean = 'and', $not = false)
orWhereNull($column)
whereNotNull($column, $boolean = 'and')
orWhereNotNull($column)
CacheStatically
This Ability
implemented a very simple cache system: Caching all method returns, and delete them all when creating/updating/deleting, you can clear cache manually too.
Once you use this Ability
, everything is automatic. all()
, find()
, paginate()
and others will go through the cache logic, if any cached return be found, then no database query will be executed. Different method has different cache key, even applying query will change the cache key.
This Ability
may not be much practical in large project, but it shows the flexibility of Housekeeper
, and other cache system is in the roadmap.
Examples
Wrapped methods has their own cache:
API
enableCache()
Enable cache system.
disableCache()
Disable cache system.
isCacheEnabled()
Indicate whether cache system is enabled or not.
clearCache()
Delete all caches of this repository.
Guardable
Housekeeper
ignored Mass Assignment Protection
by default, use this Ability
if you need it.
Guardable
disabled Mass Assignment Protection
by default too, you have to turn it on manually.
Examples
API
guardUp()
Enable Mass Assignment Protection
。
guardDown()
Disable Mass Assignment Protection
。
isGuarded()
Whether or not the Mass Assignment Protection
is enabled.
SoftDeletes
To utilize the SoftDeletes
trait of the Eloquent
, you should use this Ability
in your repository.
API
startWithTrashed()
Include soft deletes.
startWithTrashedOnly()
Include soft deletes only.
forceDelete($id)
Hard delete a record by primary key.
Arguments
$id
restore($id)
Restore a soft-deleted record by primary key.
Arguments
$id
Console Commands
Create a new repository:
Create a new repsitory and a new model:
Create a new repository with some Abilities
:
Issue
If you have any question about Housekeeper
, feel free to create an issue, I'll reply you ASAP.
Any useful pull request are welcomed too.
Lisence
Licensed under the APACHE LISENCE 2.0
Credits
Thanks to prettus/l5-repository for inspiring.
Thanks to sunkey for the awesome LOGOs!
Thanks to @DarKDinDoN, @Bruce Peng, @FelipeUmpierre, @rsdev000 for your contributions!
Thanks to Laravel for making our life easier!