开发crmeb的接口逻辑与技术实现。有俩个版本PHP版本和JAVA版本,JAVA只熟悉基本语法,所以以PHP版本为源码进行的二次开发相关整理。整体而言,电商业务在web生态圈里面比较复杂,涉及到的技术栈也相对比较多。
1.默认的模板 首页初始化接口 转载了非常多的信息 /api/diy?id=0&did=0&version=221。
该接口直接请求的是 controller/api/Common.php 文件里面的diy内容,由路由api/diy 指向common.diy
核心执行代码:
d
a
t
a
=
a
p
p
(
)
−
>
m
a
k
e
(
D
i
y
R
e
p
o
s
i
t
o
r
y
:
:
c
l
a
s
s
)
−
>
s
h
o
w
(
(
i
n
t
)
data = app()->make(DiyRepository::class)->show((int)
data=app()−>make(DiyRepository::class)−>show((int)merId, (int)$id, 1);
通过 app()->make 创建或获取 DiyRepository 类的实例。
调用实例的 show 方法,传入商户ID (merId)、记录ID (id) 和常数 1 作为参数。
返回查询的结果 $data
可以看到这里传入的参数默认情况下是0,出现的数据是平台数据
后台是可以直接使用diy模式进行前端模板配置,在开始没看懂,试图改代码来控制这块,发现逻辑非常深,后面才发现其实后台是可以进行改动的。后台——装修——页面装修 直接进行文字改动即可。
2,模块的认识, 一元抢购路径: 从route里面分组可查看
api/store/product/one/lst?page=1&limit=10
路由指向:
Route::group(‘store/product’, function () {Route::get(‘one/lst’, ‘StoreProductOne/lst’)); 最外一层是API,通过层层指向,可以看到
controller/api/store/product/StoreProductOne.php 文件里面
该控制器跳转到: (crmeb的模型后缀都带了Dao做内部识别)
common/dao/store/product/ProductDao.php
$count = $query->count(); //组装拼接了各种逻辑查询条件后,最后count一次
$list = $query->page($page, $limit)->setOption('field', [])->field($field)->select(); //返回输出结果到前端
return compact('count', 'list');//将变量作为数组键值返回给前端
3.理解dao的类用法 crmeb自创的一个方法
dao位于数据模型model层与逻辑处理层repository之间,处理每个特定逻辑数据库操作或有共性的查询、操作等
每一个dao对应一个model,比如在\app\common\model下存在User模型,那么在\app\dao下必然存在一个UserDao,必需继承baseDao并实现getModel方法,关联一个model类。一个dao操作一个model类,model也只能通过这个dao被使用,不允许跨dao调用以及夸层级调用mode
系统将代码分四层: controller 层 逻辑处理层 respository 还有模型层 model 但是随着逻辑处理层也越来越需要封装,于是又定义了一层dao层(小型项目里面极少会用到四层)最简单的项目只有一层 controller层,数据库也直接db处理了,复杂点的,会有model层,专门来交互MYSQL部分,而业务逻辑更复杂一点的,会有logic层,而crmeb是更复杂的,将logic层拆成responsity层还有dao层
在crmeb里面
model层处理的最底层的核心 处理类似 数据库的硬性条件判断,比如状态变更(类似过期) 是否被删除了(软删除)但是对于dao层面而言就是删除了,一些状态码的转换,有些状态是根据时间来换算的,但是数据库层又需要设计对应时间,这些都在model层处理掉。简单而言,model对于外部而言,就是一个经过检测转化后可用的数据表。
如果要操作数据,则使用dao层,因为model层不对外暴露。暴露的dao层,处理各种复杂的组合查询逻辑。由于系统项目非常多,组合查询太常见,包括对外开放的部分查询条件。所以dao层处理查询逻辑。系统的各种联表和条件关联,大部分封装在dao层里面。
而具体的业务逻辑层,封装到了 respository里面,实现业务的最终模块,拼接各种复杂查询,还有具体的业务判断。其中跨模块调用需要
$user = app()->make(UserReposotiroy::class);
内部跨模块的调用 可以大幅度加强业务之间的关联性开发。有助于控制业务复杂度,主要有个问题在于性能出现瓶颈的时候,会比较麻烦。在早期跨模块调用开发效率高。
对外接口展示层,放入了controller里面(大型项目,的接口层 主要处理数据合法性 还有格式的输出),包括加锁之类的操作(需要根据具体需要去进行实现)这一层基本没有太多逻辑,都是去调用respository
4.依赖注入的理解
这是tp6开始采用的思想,crmeb里面基本都是依赖注入模式实现方法。这里需要理解什么是依赖注入,先看普通的PHP代码:
<?php
//定义一个普通的数据库链接类
class DatabaseConnection {
public function connect() {
// 数据库连接逻辑
echo "Connected to the database.";
}
}
//我们定义了我们要使用
class UserRepository {
private $dbConnection;
public function __construct() {
//我们在内部实例化数据库
$this->dbConnection = new DatabaseConnection();
}
public function getUser($userId) {
$this->dbConnection->connect();
// 获取用户数据的逻辑
echo "Retrieved user with ID: $userId";
}
}
//实例化的时候,直接读取内部方法
$userRepo = new UserRepository();
//这个符合我们之前编程的思维习惯,因为我们就是在使用UserRepository的类
$userRepo->getUser(1);
?>
改用依赖注入模式开发:
<?php
interface DatabaseConnectionInterface {
public function connect();
}
//同样定义一组类的实现
class MySQLDatabaseConnection implements DatabaseConnectionInterface {
public function connect() {
// 数据库连接逻辑
echo "Connected to MySQL database.";
}
}
class UserRepository {
private $dbConnection;
//这里直接 new DatabaseConnectionInterface 进去实现上述new一样的效果
public function __construct(DatabaseConnectionInterface $dbConnection) {
$this->dbConnection = $dbConnection;
}
//获取相关数据
public function getUser($userId) {
$this->dbConnection->connect();
// 获取用户数据的逻辑
echo "Retrieved user with ID: $userId";
}
}
// 注册依赖 可以是mysql 也可以是mongdb或者redis 都是数据库类层
$dbConnection = new MySQLDatabaseConnection();
//降上述依赖注入,但是$dbConnection灵活了很多,直接将容器给复用了
$userRepo = new UserRepository($dbConnection);
$userRepo->getUser(1);
?>
回到crmeb里面
m
a
k
e
=
a
p
p
(
)
−
>
m
a
k
e
(
S
t
o
r
e
O
r
d
e
r
R
e
p
o
s
i
t
o
r
y
:
:
c
l
a
s
s
)
;
(只要调用
m
a
k
e
方法的时候
,
make = app()->make(StoreOrderRepository::class); (只要调用make方法的时候,
make=app()−>make(StoreOrderRepository::class);(只要调用make方法的时候,this->dao 获得了new StoreOrderRepository() )
app() 是一个公共方法,主要读取容器的实例化,如果实例化过就读取之前实例化过的容器,用make方法,注入StoreOrderRepository::class这个类到容器里面,其中容器里面make之后,获得了oneProductSearch方法
$query =
t
h
i
s
−
>
d
a
o
−
>
o
n
e
P
r
o
d
u
c
t
S
e
a
r
c
h
(
this->dao->oneProductSearch(
this−>dao−>oneProductSearch(where);。
这样app()容器承载不同的类,但是基础输出方法保持不变。如果历史上实例化过,直接调实例化过的类出来(实现按需加载),如果没实例化过,就会自动实例化该类。
作为简单的对比,引用类之后,我们在使用的地方 $StoreOrderRepositoryModel = new StoreOrderRepository() 这种用法最大的问题点在于,第二次如果我们调用的方法里面如果又要使用该类里面的另外一个方法,我们不得不又new 一次,当系统复杂到要跨几个控制器去调这些方法的时候,基本只能在不同的控制器里面去new,对资源消耗比较大。
而有了容器,可以统一管理,让容器不用反复实例化,大大节约内存效率。而如果是需要对某些特殊的类使用前进行处理,也可以通过容器统一管理(比如某个合法参数的导入),所以依赖注入实现是一个巨大的优化。