MVC(Model-View-Controller) 是 PHP 开发中常用的架构模式,大部分项目构建都是基于这种模式。
模型 Model – 连接和操作数据库数据。
控制器 Controller - 负责响应用户请求、准备数据,以及决定如何展示数据。
视图 View – 负责渲染数据,通过 HTML 方式呈现给用户。
Model 操作数据
Controller 控制器
View 视图
本文 PHP 演示均使用 ThinkPHP6.0
模型 Model 使用习惯
项目中一般设置 后台(Admin)、Web端(Index)、接口(Api) 三个大的模块。往往 Web端(Index) 和 接口(Api) 会共用一个 Model 层,而 后台(Admin) 因为涉及大量增删改查的动作,我一般会给 后台(Admin) 单独创建一个 Model 层。
# 后台使用
namespace app\Model\admin;
# web、Api使用
namespace app\Model;
在 ProductModel 中创建几个常用方法:
<?php
namespace app\Model\admin;
use think\Db;
class ProductModel
{
/**
* Get Product
* 获取单个产品
* @param array $params
* @return array
*/
public function getProduct($params = []) {}
/**
* Get Products
* 获取多个产品
* @param array $params
* @return array
*/
public function getProducts($params = []) {}
/**
* Create Product
* 创建产品
* @param array $params
* @return array
*/
public function create($params = []) {}
/**
* Update Product
* 更新产品
* @param array $params
* @return array
*/
public function update($params = [], $id) {}
}
需要注意,方法中使用传递数组 $params = [] 的方式,这样在项目后期可以提升代码的观赏度,避免出现以下情况:
public function getProducts($id, $category_id = '', $paginate = 1, $barand_id = '', ...) {}
当存在少量参数时,在当前方法中处理参数:
public function getProduct($params = [])
{
$query = Db::name('product');
if (isset($params['id'])) $query->where('id', $params['id']);
if (isset($params['status'])) $query->where('status', $params['status']);
$product = $query->find();
return $product;
}
当存在大量参数时,可使用 private 辅助方法处理参数:
public function getProducts($params = [])
{
$query = Db::name('product');
$this->setGetProductsParams($query, $params);
$product = $query->find();
return $product;
}
private function setGetProductsParams($query, $params = [])
{
if (isset($params['category_id'])) $query->where('category_id', $params['category_id']);
if (isset($params['brand_id'])) $query->where('brand_id', $params['brand_id']);
if (isset($params['status'])) $query->where('status', $params['status']);
if (isset($params['type'])) $query->where('type', $params['type']);
}
有时会需要在某个方法中调取不同类型的数据,即需要支持数组、又需要支持对象,或是框架带分页数据。这里我常使用多个方法处理,并不是在一个方法中通过不同参数返回不同类型的数据。
/**
* Get Products
* 获取多个产品
* @param array $params
* @return array
*/
public function getProducts($params = [])
{
$products = Db::name('product')->select()->toArray();
return $products;
}
/**
* Get Products
* 获取多个产品
* @param array $params
* @return object
*/
public function getProductsObject($params = [])
{
$products = Db::name('product')->select();
return $products;
}
/**
* Get Products
* 获取多个产品
* @param array $params
* @return object 分页
*/
public function getProductsPage($params = [])
{
$products = Db::name('product')->paginate();
return $products;
}
控制器 Controller 使用习惯
增删改查常用于后台,我习惯定义的方法名:
# 列表页
public function index() {}
# 新增页
public function create() {}
# 保存数据
public function store() {}
# 编辑页
public function edit() {}
# 更新数据
public function update() {}
# 非物理删除数据
public function delete() {}
# 物理删除数据
public function destory() {}
# 其它方法
......
MVCR
有些项目一般选择在模型 Model 与控制器 Controller 之间加一层逻辑处理的模块,我习惯使用 R(Repository:仓库、储藏室)命名(网上也有说使用 I 命名)。
通俗点讲,就是保持了 Model 的共用性、整洁性和 Controller 的整洁性,在 Repository 中处理较为复杂的逻辑。下面我们用两个示例来简单说明下 Repository 的作用。
1,查询产品,并修改结果数据格式:
在 ProductModel 中创建查询多个产品的方法:
<?php
namespace app\Model\admin;
use think\Db;
class ProductModel
{
public function getProducts() {}
}
通常逻辑我们会在控制器中直接调用该方法。这里我们改变下思路使用 ProductRepository 来获取数据,并修改产品创建时间格式:
<?php
namespace app\Repository\admin;
use app\Model\admin\ProductModel;
class ProductRepository
{
public function getProducts()
{
$products = app(ProductModel::class)->getProducts();
foreach ($products as $key => $value) {
$products[$key]['create_time'] = date('Y-m-d', $value['create_time']);
}
}
}
最后,在控制器中使用 ProductRepository 中的 getProducts 方法。
2,用户登录: UserModel 中查询,更新方法:
<?php
namespace app\Model\admin;
use think\Db;
class UserModel
{
public function getUser($params = []) {}
public function update($params = [], $id) {}
}
UserRepository 中登录方法:
<?php
namespace app\Repository\admin;
use app\Model\admin\UserModel;
class UserRepository
{
public function login($username, $password)
{
// 验证信息
$user = app(UserModel)->getUser(['username' => $username, 'password' => $password]);
if (!$user) return arrayFailed('login failed');
// 登录成功后续操作
app(UserModel)->update(['last_login_time' => time()], $user->id);
}
}
UserController 中使用 UserRepository 中的 login 方法:
<?php
namespace app\Repository\api;
use think\Request;
use app\Model\admin\UserRepository;
class UserController
{
public function login(Request $request)
{
$res = app(UserRepository::class)->login($request->username, $request->password);
}
}
上面两个示例简单展示了在 Repository 中,处理结果数据与操作业务逻辑。这里也建议项目中加入 Repositoy 层,在保持代码整洁的同时,也有灵活的扩展性。