方法容器-流程控制编写模式 控制器编写模式 2

第二部分 是思考时间 主要考虑 1中的思想的代码架构

我这个模式和Repository模式 有点像 都是把业务的方法分层
甚至可以说是对Repository模式的优化 或者说更彻底的运用仓库模式
把仓库的功能提升,仓库不在是仓库 是一个控制流程

我的模式目的是两个 代码优雅 代码量减少(单个方法是增多 但是总的来看应该是减少的)

以下是把Repository模式融入进我的模式的特点

方法容器中有仓库类
仓库类中有各自的方法

方法容器中调用的是仓库类的方法
把方法内聚 同种方法写在同一个仓库类中
可以直接使用别人的repository的包为基类的类 作为我的仓库类

……
包已经写完
laravel-function-flow

使用代码为

首先用composer加载包

composer require anyuzhe/laravel-function-flow dev-master

在配置文件config/app.php的服务容器数组中加入

\Anyuzhe\LaravelFunctionFlow\FunctionFlowServiceProvider::class,

在门面数组中加入

‘Flow’ => \Anyuzhe\LaravelFunctionFlow\FlowFacade::class,

执行命令 生成配置文件

php artisan funcFlow:publish
会在config文件夹中生成function-flow.php文件
可在里面配置仓库类 类似如下

1
2
3
4
5
6
7
8
9
10
11
12
return array(
// 'Base'=>BaseController::class 类似这样的key value定义类 名称和位置 无任何限制
'Default' => '',
'GoodsRecord' => \App\Repositories\GoodsRepository::class,
'Picture' => \App\Repositories\PicturesRepository::class,
'Store' => \App\Repositories\StoresRepository::class,
'Goods' => \App\Repositories\GoodsRepository::class,
'GoodsRecord' => \App\Repositories\GoodsRecordsRepository::class,
'Response' => \App\ZL\ResponseLayout::class,
'Qrcode' => \App\Repositories\QrcodesRepository::class,
'User' => \App\Repositories\UsersRepository::class,
);

以下是控制器中的使用示例

1
2
3
4
5
6
7
8
public function bindRecord(Request $request)
{
return \Flow::setLastFunc(['Response/flowReturn'])->setParam($request->all())->flow([
['Store/getIdByNo'],
['User/bindRecord'],
['User/checkMemberExist'],
])['response'];
}

首先除了flow方法。别的方法调用都是返回对象本身 所以可以链式调用 以上是facade方式的调用
再看一下这个详细的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public function beforeStore($id, $data)
{
$data['cover_url'] = 'http://weiyicrm.oss-cn-shanghai.aliyuncs.com/ico-fuzhaung.png';
$data['input_goods_no'] = isset($data['goods_no'])?$data['goods_no']:null;
$data['id'] = $id;
//setParam方法是设置运行中的参数 可以是数组 或者是两个参数键值的形式
return \Flow::setParam($data)->flow([ //flow为主运行方法
['Store/getOneId'],
// 数组第二个参数可以设置函数的额外参数 第三个参数是一个缓存的时间值可以设置是否缓存 单位为分钟
['Qrcode/generateGoodsNoAndCreateQrcodeByNum',['created_pic'=>false]],
['Picture/getIds'],
['Picture/getModelByIds'],
['Goods/getGoodsNo'],
['Goods/findByNo'],
['Goods/updateByStock'],
['Goods/updateBySell'],
['Goods/createOne'],
['Qrcode/bingQrcodeGoodsNo'],//
['Qrcode/bingQrcodeLabelNo'],//
['GoodsRecord/updateOne'],
['Response/flowReturn'],
])['response'];

此例子中并没有使用setLastFunc方法(用来设置最后运行方法的)
需要注意的是缓存是用了类名+方法名+参数转成字符串的值作为缓存的键名。
可以适用于一些场景 可以配合函数输出缓存的依据参数 配合使用应该还不错

最后看一下 几个方法的实例 了解下方法的编写
注意方法中的参数都是通过方法容器自动传入的 如果方法容器的参数数组中不存在并且没有默认值 会传入null
flow方法会把方法容器的parameters成员返回 也就是所有的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
这一用来返回最后的reponse数组的方法。 判断在别的方法中是否输出了错误码和错误信息
public function flowReturn($res,$errcode,$errmsg,$msg)
{
if(!$errcode){
$data['status'] = 1;
$data['data'] = $res;
$data['msg'] = $msg?$msg:'Success';
}else{
$data['status'] = $errcode;
$data['data'] = null;
$data['msg'] = $errmsg?$errmsg:'error';
}
return ['response'=>$data];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public function getOneId()
{
$user = Auth::user();
if($user) {
$stores = $user->stores;
if ($stores->count() == 1) {
//最后输出的数组 会合并入方法容器的参数数组中 之后的方法中 可以申明参数 只要变量名与参数名相同 就可以自动传入
return ['store_id'=>$stores->first()->id];
}
}
//这里返回的skip是可以跳过之后的一些方法 直接运行想要的方法 可以作为报错后的处理 这里出错 所以返回了错误码和错误信息
return ['skip'=>'flowReturn','store_id'=>null,'errcode'=>ErrorCode::$canNotFindStoreError['code'],'errmsg'=>ErrorCode::$canNotFindStoreError['msg']];
}
1
2
3
4
5
6
7
8
9
10
11
public function getIdByNo($store_no)
{
if($store_no){
$store = $this->findBy('identifying',$store_no);
if($store){
return ['store_id'=>$store->id];
}
}
//这里返回的next为false 会让方法容器不执行之后的方法。直接运行lastFunc(如果定义了的话)ps:可以把最后的返回参数处理函数定义为lastFunc
return ['next'=>false,'store_id'=>null,'errcode'=>ErrorCode::$canNotFindStoreError['code'],'errmsg'=>ErrorCode::$canNotFindStoreError['msg']];
}