描述
根据ThinkPHP5手册的说明,模型能进行分层:
通常情况下,不同的分层模型仍然是继承系统的\think\Model类或其子类,所以,其基本操作和Model类的操作是一致的。
例如在index模块的设计中需要区分数据层、逻辑层、服务层等不同的模型层,我们可以在模块目录下面创建model、logic和service目录,把对用户表的所有模型操作分成三层:
数据层:
app\index\model\User
用于定义数据相关的自动验证和自动完成和数据存取接口
逻辑层:
app\index\logic\User
用于定义用户相关的业务逻辑
服务层:
app\index\service\User
用于定义用户相关的服务接口等
解决方案
所有的层全部继承Model类,因此受到某个项目的启发,可以在基类添加如下语句使其使用魔术方法加载各层实例方法。
- 在common.php添加字符串处理函数
/**
* 魔术方法获取逻辑层、模型层、验证层
*
* @author Jake
* @param $str
* @param $prefix
* @return bool
*/
function str_prefix($str, $prefix)
{
return strpos($str, $prefix) === 0 ? true : false;
}
function sr($str = '', $target = '', $content = '')
{
return str_replace($target, $content, $str);
}
- 在Controller父类添加魔术方法处理
public function __get($logicName)
{
$layer = $this->getLayerPre($logicName);
$model = sr($logicName, $layer);
return VALIDATE_LAYER_NAME == $layer ? validate($model) : model($model, $layer);
}
protected function getLayerPre($name)
{
$layer = false;
$layer_array = [MODEL_LAYER_NAME, LOGIC_LAYER_NAME, VALIDATE_LAYER_NAME, SERVICE_LAYER_NAME];
foreach ($layer_array as $v)
if (str_prefix($name, $v)) {
$layer = $v;
break;
}
return $layer;
}
- 入口文件添加常量define
define('LOGIC_LAYER_NAME' , 'logic');
define('MODEL_LAYER_NAME' , 'model');
define('SERVICE_LAYER_NAME' , 'service');
define('CONTROLLER_LAYER_NAME' , 'controller');
define('LIBRARY_LAYER_NAME' , 'library');
define('VALIDATE_LAYER_NAME' , 'validate');
define('VIEW_LAYER_NAME' , 'view');
当然也可将魔术方法封装成一个trait文件,随时引用
<?php
/**
* Created by IntelliJ IDEA.
* User: Jake
* Date: 2019/8/23
* Time: 16:47
*/
namespace app\common\traits;
define('LOGIC_LAYER_NAME' , 'logic');
define('MODEL_LAYER_NAME' , 'model');
define('SERVICE_LAYER_NAME' , 'service');
define('CONTROLLER_LAYER_NAME' , 'controller');
define('LIBRARY_LAYER_NAME' , 'library');
define('VALIDATE_LAYER_NAME' , 'validate');
define('VIEW_LAYER_NAME' , 'view');
trait Magic
{
public function __get($logicName)
{
$layer = $this->getLayerPre($logicName);
$model = sr($logicName, $layer);
return VALIDATE_LAYER_NAME == $layer ? validate($model) : model($model, $layer);
}
protected function getLayerPre($name)
{
$layer = false;
$layer_array = [MODEL_LAYER_NAME, LOGIC_LAYER_NAME, VALIDATE_LAYER_NAME, SERVICE_LAYER_NAME];
foreach ($layer_array as $v)
if (str_prefix($name, $v)) {
$layer = $v;
break;
}
return $layer;
}
}
实现效果
$this->logicFoo->bar()
等效于new namespace\logic\Foo() -> bar()
$this->modelFoo->bar()
等效于new namespace\model\Foo() -> bar()
$this->serviceFoo->bar()
等效于new namespace\service\Foo() -> bar()
$this->controllerFoo->bar()
等效于new namespace\controller\Foo() -> bar()
$this->libraryFoo->bar()
等效于new namespace\library\Foo() -> bar()
$this->validateFoo->bar()
等效于new namespace\validate\Foo() -> bar()
$this->viewFoo->bar()
等效于new namespace\view\Foo() -> bar()
潜在缺点(个人看法)
- 分层需要很明细,如果不同app之间需要模块重用的话,需要将模块放置到common文件夹内。
- 处理模板view的模块,最后还是交给Controller处理,复杂逻辑交给Logic处理。