Laravel 5 Repositories is used to abstract the data layer, making our application more flexible to maintain.
laravel 5库用于laravel抽象数据层,使我们的应用程序的维护更加灵活。
You want to know a little more about the Repository pattern? Read this great article.
Execute the following command to get the latest version of the package:
composer require prettus/l5-repository
In your config/app.php
add Prettus\Repository\Providers\RepositoryServiceProvider::class
to the end of the providers
array:
'providers' => [
...
Prettus\Repository\Providers\RepositoryServiceProvider::class,
],
If Lumen
$app->register(Prettus\Repository\Providers\LumenRepositoryServiceProvider::class);
Publish Configuration
php artisan vendor:publish
- all($columns = array('*'))
- first($columns = array('*'))
- paginate($limit = null, $columns = ['*'])
- find($id, $columns = ['*'])
- findByField($field, $value, $columns = ['*'])
- findWhere(array $where, $columns = ['*'])
- findWhereIn($field, array $where, $columns = [*])
- findWhereNotIn($field, array $where, $columns = [*])
- create(array $attributes)
- update(array $attributes, $id)
- updateOrCreate(array $attributes, array $values = [])
- delete($id)
- orderBy($column, $direction = 'asc');
- with(array $relations);
- has(string $relation);
- whereHas(string $relation, closure $closure);
- hidden(array $fields);
- visible(array $fields);
- scopeQuery(Closure $scope);
- getFieldsSearchable();
- setPresenter($presenter);
- skipPresenter($status = true);
- pushCriteria($criteria)
- popCriteria($criteria)
- getCriteria()
- getByCriteria(CriteriaInterface $criteria)
- skipCriteria($status = true)
- getFieldsSearchable()
- setCacheRepository(CacheRepository $repository)
- getCacheRepository()
- getCacheKey($method, $args = null)
- getCacheMinutes()
- skipCache($status = true)
- present($data);
- setPresenter(PresenterInterface $presenter);
- presenter();
- apply($model, RepositoryInterface $repository);
- transform();
通常创建模型,都会设置可批量赋值的字段。
class Post extends Eloquent { // or Ardent, Or any other Model Class
protected $fillable = [
'title',
'author',
...
];
...
}
use Prettus\Repository\Eloquent\BaseRepository;
class PostRepository extends BaseRepository {
/**
* Specify Model class name
*
* @return string
*/
function model()
{
return "App\\Post";
}
}
通过创建器轻松创建的你仓库
你首先必须配置你的仓库文件的储存位置。默认情况下默认文件夹是‘app’,默认的命名空间是‘App’。 请注意:paths数组的值既作为文件路径,又作为命名空间路径。不过是放松的,不区分‘/’(正斜杠)和‘\’(反斜杠)
...
'generator'=>[
'basePath'=>app_path(),
'rootNamespace'=>'App\\',
'paths'=>[
'models' => 'Entities',
'repositories' => 'Repositories',
'interfaces' => 'Repositories',
'transformers' => 'Transformers',
'presenters' => 'Presenters',
'validators' => 'Validators',
'controllers' => 'Http/Controllers',
'provider' => 'RepositoryServiceProvider',
'criteria' => 'Criteria',
]
]
您可能希望将项目文件夹的根保存到app下,并添加另一个命名空间,例如
...
'generator'=>[
'basePath' => base_path('src/Lorem'),
'rootNamespace' => 'Lorem\\'
]
另外:你可能希望自定义生成的类最终被保存的地方,可以自定义编辑路径完成。例如:
'generator'=>[
'basePath'=>app_path(),
'rootNamespace'=>'App\\',
'paths'=>[
'models'=>'Models',
'repositories'=>'Repositories\\Eloquent',
'interfaces'=>'Contracts\\Repositories',
'transformers'=>'Transformers',
'presenters'=>'Presenters'
'validators' => 'Validators',
'controllers' => 'Http/Controllers',
'provider' => 'RepositoryServiceProvider',
'criteria' => 'Criteria',
]
]
生成你需要的一切模型,运行一下命令:
php artisan make:entity Post
这个命令将创建控制器(controller)、验证器(Validator)、模型(Model)、仓库(Repository)、呈现器(Presenter)和转换器(Transform)的类文件。它还将创建一个新的服务提供商,将用于绑定具有相应存储库接口的功能的存储库,加载它,添加到你的AppServiceProvider@register中:
$this->app->register(RepositoryServiceProvider::class);
您也可以通过存储库命令的选项,因为这个命令是一个包装器;你可以单独为你的模型生成一个仓库,使用下面的命令
php artisan make:repository Post
为你的文章添加Blog命名空间,使用一下命令
php artisan make:repository "Blog\Post"
创建时设置可填充字段
php artisan make:repository "Blog\Post" --fillable="title,content"
创建时设置可填充字段,迁移文件及验证规则:
php artisan make:entity Cat --fillable="title:string,content:text" --rules="title=>required|min:2, content=>sometimes|min:10"
在你的route.php文件中创建一个资源路由(含增删改查)
Route::resource('cats', CatsController::class);
在运行命令时,你可以设置默认的Entities文件夹和Repositories里的文件夹。
这样做,只是现在你做的是为您的真正的存储库绑定它的接口,例如在您自己的存储库服务提供商。
App::bind('{YOUR_NAMESPACE}Repositories\PostRepository', '{YOUR_NAMESPACE}Repositories\PostRepositoryEloquent');
使用:
public function __construct({YOUR_NAMESPACE}Repositories\PostRepository $repository){
$this->repository = $repository;
}
或者你可以使用artisan命令进行绑定
php artisan make:bindings Cats
namespace App\Http\Controllers;
use App\PostRepository;
class PostsController extends BaseController {
/**
* @var PostRepository
*/
protected $repository;
public function __construct(PostRepository $repository){
$this->repository = $repository;
}
....
}
从仓库中获取全部数据
$posts = $this->repository->all();
从仓库中获取分页数据
$posts = $this->repository->paginate($limit = null, $columns = ['*']);
通过id获取结果集
$post = $this->repository->find($id);
模型隐藏属性
$post = $this->repository->hidden(['country_id'])->find($id);
仅显示模型的特定属性
$post = $this->repository->visible(['id', 'state_id'])->find($id);
加载模型的关联关系
$post = $this->repository->with(['state'])->find($id);
通过字段值匹配获取结果集
$posts = $this->repository->findByField('country_id','15');
根据多个字段值匹配获取结果集
$posts = $this->repository->findWhere([
//Default Condition =
'state_id'=>'10',
'country_id'=>'15',
//Custom Condition
['columnName','>','10']
]);
根据字段值是否存在与多个value值中获取结果集(in--子查询)
$posts = $this->repository->findWhereIn('id', [1,2,3,4,5]);
根据字段值是否不存在与多个value值中获取结果集(NotIn--子查询)
$posts = $this->repository->findWhereNotIn('id', [6,7,8,9,10]);
使用自定义查询范围获取全部数据
$posts = $this->repository->scopeQuery(function($query){
return $query->orderBy('sort_order','asc');
})->all();
在仓库中创建新的记录
$post = $this->repository->create( Input::all() );
在仓库中更新记录
$post = $this->repository->update( Input::all(), $id );
在仓库中删除记录
$this->repository->delete($id)
php artisan make:criteria My
标准是一种通过根据你需要的应用特定条件来改变查询库的方法,你可以在你的仓库中添加多个标准
use Prettus\Repository\Contracts\RepositoryInterface;
use Prettus\Repository\Contracts\CriteriaInterface;
class MyCriteria implements CriteriaInterface {
public function apply($model, RepositoryInterface $repository)
{
$model = $model->where('user_id','=', Auth::user()->id );
return $model;
}
}
namespace App\Http\Controllers;
use App\PostRepository;
class PostsController extends BaseController {
/**
* @var PostRepository
*/
protected $repository;
public function __construct(PostRepository $repository){
$this->repository = $repository;
}
public function index()
{
$this->repository->pushCriteria(new MyCriteria1());
$this->repository->pushCriteria(MyCriteria2::class);
$posts = $this->repository->all();
...
}
}
根据标准获取结果集
$posts = $this->repository->getByCriteria(new MyCriteria());
在你的仓库中设置默认的标准(条件)类
use Prettus\Repository\Eloquent\BaseRepository;
class PostRepository extends BaseRepository {
public function boot(){
$this->pushCriteria(new MyCriteria());
// or
$this->pushCriteria(AnotherCriteria::class);
...
}
function model(){
return "App\\Post";
}
}
在使用其他任何方法之前使用skipCriteria
$posts = $this->repository->skipCriteria()->all();
使用popCriteria
删除一个标准
$this->repository->popCriteria(new Criteria1());
// or
$this->repository->popCriteria(Criteria1::class);
请求标准是一个标准的实现,它使用滤器在从请求发送的参数中执行。
你可以执行一个动态搜索,过滤数据和自定义查询。
要使用你仓库中的标准,你可以在你的仓库的boot
方法中添加一个新的标准,或直接使用在你的控制器中,为了过滤掉少数的请求
####Enabling in your Repository --在你的仓库中使用
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;
class PostRepository extends BaseRepository {
/**
* @var array
*/
protected $fieldSearchable = [
'name',
'email'
];
public function boot(){
$this->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
...
}
function model(){
return "App\\Post";
}
}
注意:你定义的字段在模型中可以搜索到。
在你的仓库中设置**$fieldSearchable**通过字段名或与字段的关系来进行搜索
protected $fieldSearchable = [
'name',
'email',
'product.name'
];
你可以设置默认执行查询的条件类型,默认为"="
protected $fieldSearchable = [
'name'=>'like',
'email', // Default Condition "="
'your_field'=>'condition'
];
####Enabling in your Controller --在你的控制器中使用
public function index()
{
$this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
$posts = $this->repository->all();
...
}
请求所有的数据不需要过滤器
http://prettus.local/users
[
{
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00"
},
{
"id": 2,
"name": "Lorem Ipsum",
"email": "[email protected]",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00"
},
{
"id": 3,
"name": "Laravel",
"email": "[email protected]",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00"
}
]
根据请求在仓库中进行搜索
http://prettus.local/users?search=John%20Doe
or
http://prettus.local/users?search=John&searchFields=name:like
or
http://prettus.local/[email protected]&searchFields=email:=
or
http://prettus.local/users?search=name:John Doe;email:[email protected]
or
http://prettus.local/users?search=name:John;email:[email protected]&searchFields=name:like;email:=
[
{
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00"
}
]
过滤字段
http://prettus.local/users?filter=id;name
[
{
"id": 1,
"name": "John Doe"
},
{
"id": 2,
"name": "Lorem Ipsum"
},
{
"id": 3,
"name": "Laravel"
}
]
结果集排序
http://prettus.local/users?filter=id;name&orderBy=id&sortedBy=desc
[
{
"id": 3,
"name": "Laravel"
},
{
"id": 2,
"name": "Lorem Ipsum"
},
{
"id": 1,
"name": "John Doe"
}
]
通过相关表进行排序
http://prettus.local/users?orderBy=posts|title&sortedBy=desc
Query will have something like this
查询语句中将有:
...
INNER JOIN posts ON users.post_id = posts.id
...
ORDER BY title
...
http://prettus.local/users?orderBy=posts:custom_id|posts.title&sortedBy=desc
Query will have something like this
...
INNER JOIN posts ON users.custom_id = posts.id
...
ORDER BY posts.title
...
添加关联关系
http://prettus.local/users?with=groups
####Overwrite params name --覆盖参数名称
你可以在配置中更改参数的名称,文件config/repository.php中
轻松添加一层缓存到你的仓库中
实现接口CacheableInterface
和使用CacheableRepository
Trait
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Traits\CacheableRepository;
class PostRepository extends BaseRepository implements CacheableInterface {
use CacheableRepository;
...
}
这样做,你的存储库将被缓存,当创建一条新纪录时,缓存将被清除(修改或删除)
你还可以在 config/repository.php 中更改缓存设置,也可以直接在你的仓库中进行修改
config/repository.php
'cache'=>[
//Enable or disable cache repositories 是否使用
'enabled' => true,
//Lifetime of cache 缓存时间(分钟)
'minutes' => 30,
//Repository Cache, implementation Illuminate\Contracts\Cache\Repository
//仓库缓存,实现Illuminate\Contracts\Cache\Repository
'repository'=> 'cache',
//Sets clearing the cache 设置清除缓存
'clean' => [
//Enable, disable clearing the cache on changes
'enabled' => true,
'on' => [
//Enable, disable clearing the cache when you create an item
'create'=>true,
//Enable, disable clearing the cache when upgrading an item
'update'=>true,
//Enable, disable clearing the cache when you delete an item
'delete'=>true,
]
],
'params' => [
//Request parameter that will be used to bypass the cache repository
//将用于绕过缓存库的请求参数
'skipCache'=>'skipCache'
],
'allowed'=>[
//Allow caching only for some methods
//只允许一些方法缓存
'only' =>null,
//Allow caching for all available methods, except
//排除一些方法不进行缓存
'except'=>null
],
],
它是可以直接在仓库中覆盖这些设置的
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Traits\CacheableRepository;
class PostRepository extends BaseRepository implements CacheableInterface {
// Setting the lifetime of the cache to a repository specifically
protected $cacheMinutes = 90;
protected $cacheOnly = ['all', ...];
//or
protected $cacheExcept = ['find', ...];
use CacheableRepository;
...
}
缓存方法可选值:all, paginate, find, findByField, findWhere, getByCriteria
Requires prettus/laravel-validator. composer require prettus/laravel-validator
轻松验证 prettus/laravel-validator
在下面的列子中,我们定义了一些创建和版本的规则
use \Prettus\Validator\LaravelValidator;
class PostValidator extends LaravelValidator {
protected $rules = [
'title' => 'required',
'text' => 'min:3',
'author'=> 'required'
];
}
定义特定的规则,如下:
use \Prettus\Validator\Contracts\ValidatorInterface;
use \Prettus\Validator\LaravelValidator;
class PostValidator extends LaravelValidator {
protected $rules = [
ValidatorInterface::RULE_CREATE => [
'title' => 'required',
'text' => 'min:3',
'author'=> 'required'
],
ValidatorInterface::RULE_UPDATE => [
'title' => 'required'
]
];
}
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;
class PostRepository extends BaseRepository {
/**
* Specify Model class name
*
* @return mixed
*/
function model(){
return "App\\Post";
}
/**
* Specify Validator class name
*
* @return mixed
*/
public function validator()
{
return "App\\PostValidator";
}
}
另外:不是使用类来定义它的验证规则,您可以将您的规则设置到仓库属性中,它与验证类相同的结果
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Validator\Contracts\ValidatorInterface;
class PostRepository extends BaseRepository {
/**
* Specify Validator Rules
* @var array
*/
protected $rules = [
ValidatorInterface::RULE_CREATE => [
'title' => 'required',
'text' => 'min:3',
'author'=> 'required'
],
ValidatorInterface::RULE_UPDATE => [
'title' => 'required'
]
];
/**
* Specify Model class name
*
* @return mixed
*/
function model(){
return "App\\Post";
}
}
验证已经准备好了,在失败的情况下将抛出一个异常:Prettus\Validator\Exceptions\ValidatorException
呈现器作为一个对象包装和渲染
Requires Fractal. composer require league/fractal
有两种方法来实现呈现器,首先是创建一个转换器并将它用你的呈现器中创建一个转换器类
第二种方法是使你的模型继承转换器接口(Transformable),使用默认的呈现器ModelFractarPresenter,两种方法产生的结果是相同的
php artisan make:transformer Post
这将生成下面的类
use League\Fractal\TransformerAbstract;
class PostTransformer extends TransformerAbstract
{
public function transform(\Post $post)
{
return [
'id' => (int) $post->id,
'title' => $post->title,
'content' => $post->content
];
}
}
php artisan make:presenter Post
如果你还没有创建转换器,该命令会提示你安装一个转换器
use Prettus\Repository\Presenter\FractalPresenter;
class PostPresenter extends FractalPresenter {
/**
* Prepare data to present
*
* @return \League\Fractal\TransformerAbstract
*/
public function getTransformer()
{
return new PostTransformer();
}
}
use Prettus\Repository\Eloquent\BaseRepository;
class PostRepository extends BaseRepository {
...
public function presenter()
{
return "App\\Presenter\\PostPresenter";
}
}
或者在你的控制器中使用
$this->repository->setPresenter("App\\Presenter\\PostPresenter");
如果你记录了一个呈现器有时用skippresenter()
方法或者你不想你的结果是不是由呈现器自动改变
你可以在你的模型实现像样的界面让你可以在任何时候提出你的模型,如下:
在你的模型中实现Prettus\Repository\Contracts\Presentable
接口和使用Prettus\Repository\Traits\PresentableTrait
Trait
namespace App;
use Prettus\Repository\Contracts\Presentable;
use Prettus\Repository\Traits\PresentableTrait;
class Post extends Eloquent implements Presentable {
use PresentableTrait;
protected $fillable = [
'title',
'author',
...
];
...
}
在这里,现在你可以单独提交你的模型,如下:
$repository = app('App\PostRepository');
$repository->setPresenter("Prettus\\Repository\\Presenter\\ModelFractalPresenter");
//Getting the result transformed by the presenter directly in the search
//获取又呈现器在搜索中转化的结果
$post = $repository->find(1);
print_r( $post ); //It produces an output as array 它产生一个输出为数组
...
//Skip presenter and bringing the original result of the Model
//跳过呈现器,输出Model的原始结果集
$post = $repository->skipPresenter()->find(1);
print_r( $post ); //It produces an output as a Model object 它产生一个输出为Model对象
print_r( $post->presenter() ); //It produces an output as array 它产生一个输出为数组
您可以在每一次访问跳过呈现器,并使用它直接到模型的需求,在你的仓库中设置$skipPresenter
属性为true
use Prettus\Repository\Eloquent\BaseRepository;
class PostRepository extends BaseRepository {
/**
* @var bool
*/
protected $skipPresenter = true;
public function presenter()
{
return "App\\Presenter\\PostPresenter";
}
}
namespace App;
use Prettus\Repository\Contracts\Transformable;
class Post extends Eloquent implements Transformable {
...
/**
* @return array
*/
public function transform()
{
return [
'id' => (int) $this->id,
'title' => $this->title,
'content' => $this->content
];
}
}
Prettus\Repository\Presenter\ModelFractalPresenter
是一个实现模型转换默认呈现器
use Prettus\Repository\Eloquent\BaseRepository;
class PostRepository extends BaseRepository {
...
public function presenter()
{
return "Prettus\\Repository\\Presenter\\ModelFractalPresenter";
}
}
或在你的控制器中使用
$this->repository->setPresenter("Prettus\\Repository\\Presenter\\ModelFractalPresenter");
在任何其他方法之前使用skipPresenter
$posts = $this->repository->skipPresenter()->all();
or
$this->repository->skipPresenter();
$posts = $this->repository->all();