phpno1 / architecture
an architecture for laravel
Installs: 2 016
Dependents: 0
Suggesters: 0
Security: 0
Stars: 64
Watchers: 3
Forks: 5
Open Issues: 0
Requires
- php: >=7.1
Requires (Dev)
- phpunit/phpunit: ~6.0
README
官方扩展qq群
qq:680531281
功能
项目架构分层,代码生成器,快速进入开发阶段,拆分职责降低耦合。
目录
安装
使用要求
- laravel >= 5.5
- php >= 7.1
composer
执行以下命令获取包的最新版本:
composer require phpno1/architecture
laravel
生成配置文件
php artisan vendor:publish --provider "Phpno1\Architecture\Providers\ArchitectureServiceProvider"
注册到服务容器
说明:用命令生成仓储文件时(phpno1:entity || phpno1:repository),会自动生成ArchitectureServiceProvider文件。
# 在config/app.php中 'providers' => [ // ...... App\Providers\ArchitectureServiceProvider::class, ];
配置
//architecture.php 'pagination' => [//默认分页数量 'limit' => 20 ], 'cache' => [//缓存时间 'enabled' => true, 'minutes' => 10, ], 'order' => [//排序字段 'o', ], 'generator' => [//代码生成器命名空间 'root_namespace' => 'App\\', 'namespace' => [ 'controller' => 'Backend', 'repository_eloquent' => 'Repository\\Eloquent', 'repository' => 'Repository\\Contracts', 'criteria' => 'Architecture\\Criterias', 'provider' => 'Providers\\ArchitectureServiceProvider', 'service' => 'Services', 'model' => 'Models', 'response' => 'Http\\Responses', 'filter' => 'Repository\\Filters' ] ]
命令
说明:使用命令创建仓储文件时(phpno1:entity和phpno1:repository),会自动绑定接口与实现类关系。
生成组合配置
//@params {name} 生成文件名称 //@params {--resource} 生成资源方法(参照laravel控制器 资源控制器) php artisan phpno1:entity {name} {--resource}
生成控制器
//@params {name} 控制器名称 //@params {--resource} 生成资源方法(参照laravel控制器 资源控制器) php artisan phpno1:controller {name} {--resource}
生成业务处理类
@params {name} 文件名称 @params {--resource} 生成资源方法 php artisan phpno1:service {name} {--resource}
生成扩展全局限制类
@params {name} 限制类名称 php artisan phpno1:criteria {name}
生成过滤类
@params {name} 过滤类名称 @params {--prefix=} 命名空间 @params {--sort} 排序方法 php artisan phpno1:filter {name} {--prefix=} {--sort}
生成模型类
@params {name} 模型名称 php artisan phpno1:model {name}
生成服务器提供者,用于接口绑定实体类
php artisan phpno1:provider
生成仓库类
@params {name} 仓库名称 php artisan phpno1:repository {name}
生成校验类
@params {name} 文件名称 @params {--dir=} 生成目录 php artisan phpno1:request {name} {--dir=}
生成响应类
@params {name} 文件名称 @params {--dir=} 生成目录 php artisan phpno1:response {name} {--dir=}
生成种子文件
@params {name} 文件名称 php artisan phpno1:seeder {name}
快速使用
1.执行以下命令:
php artisan phpno1:entity User --resource
生成文件 (注:以下命令生成文件路径可以通过配置修改architecture.php)
- app\Http\Controllers\Backend\UserController
- app\Services\UserService
- app\Repository\Eloquent\UserRepositoryEloquent
- app\Repository\Contracts\UserRepository
- app\Http\Requests\User\StoreRequest \UpdateRequest
- app\Http\Responses\User\IndexResponse \ShowResponse
- app\Models\UserModel
- database\factories\UserFactory
- database\migrations\UserTable
- database\seeds\UserSeeder
2.修改代码
1).控制器
<?php namespace App\Http\Controllers\Backend; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use App\Services\UserService; use App\Http\Responses\User\IndexResponse; class UserController extends Controller { private $user; public function __construct(UserService $userService) { $this->user=$userService; } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // $result=$this->user->getUsers();//这里调用是业务层资源方法 return new IndexResponse($result); }
2).响应(数据映射)
<?php namespace App\Http\Responses\User; use Illuminate\Contracts\Support\Responsable; use App\Traits\ResponseTrait; class UserIndexResponse implements Responsable { use ResponseTrait; protected $result; public function __construct($result) { $this->result = $result; } public function toResponse($request) { $data = $this->transform(); return $data; } protected function transform() { //分页数据例子 $this->result->getCollection()->transform(function ($user) { return [ 'id' => $user->id, 'name' => $user->name, ]; }); //集合数据例子 $this->result->transform(function ($user) { return [ 'id' => $user->id, 'name' => $user->name, ]; }); return $this->result; } }
方法介绍
- Contracts : 仓储业务抽象接口。
- Criterias : 全局通用业务抽取以及准对某一类业务的Scope。
- Eloquent : 仓储业务具体实现。
- Exceptions : 仓储异常处理。
- Filters : 根据参数自动过滤和排序。
- Traits : Trait封装
Phpno1\Repository\Contracts\IRepository;
- function entity();
- function all();
- function find(int $id);
- function first();
- function count();
- function findWhere(...$condition);
- function findWhereFirst(...$condition);
- function findWhereCount(...$condition);
- function paginate(int $perPage = 10);
- function create(array $properties);
- function update(int $id, array $properties);
- function delete(int $id);
- function withCriteria(...$criteria);
- function toEntity();
- function toRepository(Builder $entity);
Phpno1\Repository\Eloquent;
// 获取所有记录 $this->repository->all();
// 根据id查询单条记录 $this->repository->find(int $id);
// 获取第一条记录 $this->repository->first();
// 获取总记录数 $this->repository->count();
// 根据一个或多个 AND WHERE 条件查询。得到一个结果集 // 单个条件写法:->findWhere('name', 'tome'); // 多个条件写法:->findWhere(['name', 'tome'], ['age', '>', 20]); $this->repository->findWhere(...$condition);
// 根据一个或多个 AND WHERE 条件查询。得到一条记录。 $this->repository->findWhereFirst(...$condition);
// 根据一个或多个 AND WHERE 条件获取记录数 $this->repository->findWhereCount(...$condition);
// 获取分页数据 $this->repository->paginate(int $perPage = 10);
// 插入记录 $this->repository->create(array $properties);
// 修改记录 $this->repository->update(int $id, array $properties);
// 根据id删除 $this->repository->delete(int $id);
// 用于加载预设的自定义标准操作 (Criterias目录中的类),后面会详细介绍 $this->repository->withCriteria(...$criteria);
// 把Repository转换成Model或者Build对象,后续可以使用框架提供的ORM操作 $this->repository->toEntity();
// 把Build对象转回Repository对象 $this->repository->toRepository(Builder $entity);
初始化加载
//请重写boot方法 不要重写构造方法 function boot() { }
限制条件
编写Criteria类
namespace App\Repositories\Criterias; class ByCreateTime implements ICriteria { public function apply($entity) { return $entity->latest(); } }
使用Criteria类
public function getUserListByCreateTime() { return $this->repository ->withCriteria( new ByCreateTime() // more... )->paginate(); }
过滤条件
在Repository中配置要过滤和排序的映射字段
class UserRepositoryEloquent extends AbstractRepository implements UserRepository { // 设置过滤映射 protected $filters = [ 'email' => EmailFilter::class, 'name' => NameFilter::class, ]; public function entity() { return User::class; } // 过滤和排序在withCriteria中添加过滤和排序操作类FilterRequest public function findUserListByPage() { return $this->withCriteria( new FilterRequest($this->filters) )->paginate(); } // something... }
编写要过滤的业务
namespace App\Repositories\Filters\User; use App\Repositories\Filters\AbstractFilter; class NameFilter extends AbstractFilter { // 过滤操作 public function filter($entity, $value) { return $entity->where('name', $value); } }
编写要排序的业务
注意:如果你需要字段排序,首先需要在生成的配置文件architecture.php中定义你需要的排序接收参数
在过滤类中必须实现接口 "IOrder"!!!
namespace App\Repositories\Filters\Admin; use App\Repositories\Filters\{ AbstractFilter, IOrder }; // 需要排序,必须实现排序接口 class NameFilter extends AbstractFilter implements IOrder { // 过滤操作 public function filter($entity, $value) { return $entity->where('name', $value); } // 排序操作 public function order($entity, $direction) { return $entity->orderBy('name', $this->resolveOrderDirection($direction)); } }
传递参数进行过滤操作
// 过滤name和email http://www.phpno1.com/user?name=Anthony&email=king19800105@163.com // 过滤和排序组合。参数"o"是需要排序的字段key,value是排序规则 asc|desc,o参数是在architecture.php中配置的,可以定义多个参数。 http://www.phpno1.com/user?name=Anthony&email=king19800105@163.com&o=desc
scope
这里仓库层中的scope方法是兼容laravel模型的scope方法调用
注意如果调用scope方法请注意,必须先调用再执行withCriteria进行过滤
//模型中定义 class User extends Model { public function scopeUserFields() { return $this->select(['id','name','email']); } } //仓库中调用 class UserRepositoryEloquent extends AbstractRepository implements UserRepository { public function getUsers(int $perPage=0) { return $this->userFields()->withCriteria( new FilterRequest($this->filters) )->paginate($perPage); } }
自定义
//当Repository提供的method无法满足业务 public function do() { // 使用toEntity() 转换回Model或Build对象 return $this->repository ->toEntity() ->where(...) ->orWhere(...) ->when(...) ->get(...); }
缓存
使用CacheGenerate的trait特性 用途:当使用redis或memcahce做缓存时,方便做数据缓存操作。当然,您也可以使用Laravel框架提供的Cache。
public function getUserList() { // 参数1:缓存的key值 // 缓存中有数据则从缓存中取,没有数据则从数据库取一次放入缓存。 $this->getOrCache('getUserList', function () { return $this->paginate(); }); }
注意事项
- 建议文件生成都使用命令来操作。
- 过滤必须要继承AbstractFilter (有特殊需求的可以实现IFilter接口) ,过滤必须实现IOrder接口。
- 过滤和排序都是可选的。
- 需要排序的字段必须在architecture.php中定义你需要的排序接收参数,否则参数无法接收。
- 通过重写过滤中的mappings()方法来改变数据库字段和过滤使用的参数映射关系。
- 通过重写AbstractFilter中的resolveOrderDirection()方法来改变排序方式的映射关系。