简介

MVC(Model-View-Controller) 是 PHP 开发中常用的架构模式,大部分项目构建都是基于这种模式。

  • 模型 Model – 连接和操作数据库数据。
  • 控制器 Controller - 负责响应用户请求、准备数据,以及决定如何展示数据。
  • 视图 View – 负责渲染数据,通过 HTML 方式呈现给用户。
    1. Model 操作数据
    2. Controller 控制器
    3. View 视图

    本文 PHP 演示均使用 ThinkPHP6.0

模型 Model 使用习惯

项目中一般设置 后台(Admin)Web端(Index)接口(Api) 三个大的模块。往往 Web端(Index)接口(Api) 会共用一个 Model 层,而 后台(Admin) 因为涉及大量增删改查的动作,我一般会给 后台(Admin) 单独创建一个 Model 层。

  1. # 后台使用
  2. namespace app\Model\admin;
  3. # web、Api使用
  4. namespace app\Model;

ProductModel 中创建几个常用方法:

  1. <?php
  2. namespace app\Model\admin;
  3. use think\Db;
  4. class ProductModel
  5. {
  6. /**
  7. * Get Product
  8. * 获取单个产品
  9. * @param array $params
  10. * @return array
  11. */
  12. public function getProduct($params = []) {}
  13. /**
  14. * Get Products
  15. * 获取多个产品
  16. * @param array $params
  17. * @return array
  18. */
  19. public function getProducts($params = []) {}
  20. /**
  21. * Create Product
  22. * 创建产品
  23. * @param array $params
  24. * @return array
  25. */
  26. public function create($params = []) {}
  27. /**
  28. * Update Product
  29. * 更新产品
  30. * @param array $params
  31. * @return array
  32. */
  33. public function update($params = [], $id) {}
  34. }

需要注意,方法中使用传递数组 $params = [] 的方式,这样在项目后期可以提升代码的观赏度,避免出现以下情况:

  1. public function getProducts($id, $category_id = '', $paginate = 1, $barand_id = '', ...) {}

当存在少量参数时,在当前方法中处理参数:

  1. public function getProduct($params = [])
  2. {
  3. $query = Db::name('product');
  4. if (isset($params['id'])) $query->where('id', $params['id']);
  5. if (isset($params['status'])) $query->where('status', $params['status']);
  6. $product = $query->find();
  7. return $product;
  8. }

当存在大量参数时,可使用 private 辅助方法处理参数:

  1. public function getProducts($params = [])
  2. {
  3. $query = Db::name('product');
  4. $this->setGetProductsParams($query, $params);
  5. $product = $query->find();
  6. return $product;
  7. }
  8. private function setGetProductsParams($query, $params = [])
  9. {
  10. if (isset($params['category_id'])) $query->where('category_id', $params['category_id']);
  11. if (isset($params['brand_id'])) $query->where('brand_id', $params['brand_id']);
  12. if (isset($params['status'])) $query->where('status', $params['status']);
  13. if (isset($params['type'])) $query->where('type', $params['type']);
  14. }

有时会需要在某个方法中调取不同类型的数据,即需要支持数组、又需要支持对象,或是框架带分页数据。这里我常使用多个方法处理,并不是在一个方法中通过不同参数返回不同类型的数据。

  1. /**
  2. * Get Products
  3. * 获取多个产品
  4. * @param array $params
  5. * @return array
  6. */
  7. public function getProducts($params = [])
  8. {
  9. $products = Db::name('product')->select()->toArray();
  10. return $products;
  11. }
  12. /**
  13. * Get Products
  14. * 获取多个产品
  15. * @param array $params
  16. * @return object
  17. */
  18. public function getProductsObject($params = [])
  19. {
  20. $products = Db::name('product')->select();
  21. return $products;
  22. }
  23. /**
  24. * Get Products
  25. * 获取多个产品
  26. * @param array $params
  27. * @return object 分页
  28. */
  29. public function getProductsPage($params = [])
  30. {
  31. $products = Db::name('product')->paginate();
  32. return $products;
  33. }

控制器 Controller 使用习惯

增删改查常用于后台,我习惯定义的方法名:

  1. # 列表页
  2. public function index() {}
  3. # 新增页
  4. public function create() {}
  5. # 保存数据
  6. public function store() {}
  7. # 编辑页
  8. public function edit() {}
  9. # 更新数据
  10. public function update() {}
  11. # 非物理删除数据
  12. public function delete() {}
  13. # 物理删除数据
  14. public function destory() {}
  15. # 其它方法
  16. ......

MVCR

有些项目一般选择在模型 Model 与控制器 Controller 之间加一层逻辑处理的模块,我习惯使用 R(Repository:仓库、储藏室)命名(网上也有说使用 I 命名)。
通俗点讲,就是保持了 Model 的共用性、整洁性和 Controller 的整洁性,在 Repository 中处理较为复杂的逻辑。下面我们用两个示例来简单说明下 Repository 的作用。
1,查询产品,并修改结果数据格式:
在 ProductModel 中创建查询多个产品的方法:

  1. <?php
  2. namespace app\Model\admin;
  3. use think\Db;
  4. class ProductModel
  5. {
  6. public function getProducts() {}
  7. }

通常逻辑我们会在控制器中直接调用该方法。这里我们改变下思路使用 ProductRepository 来获取数据,并修改产品创建时间格式:

  1. <?php
  2. namespace app\Repository\admin;
  3. use app\Model\admin\ProductModel;
  4. class ProductRepository
  5. {
  6. public function getProducts()
  7. {
  8. $products = app(ProductModel::class)->getProducts();
  9. foreach ($products as $key => $value) {
  10. $products[$key]['create_time'] = date('Y-m-d', $value['create_time']);
  11. }
  12. }
  13. }

最后,在控制器中使用 ProductRepository 中的 getProducts 方法。
2,用户登录: UserModel 中查询,更新方法:

  1. <?php
  2. namespace app\Model\admin;
  3. use think\Db;
  4. class UserModel
  5. {
  6. public function getUser($params = []) {}
  7. public function update($params = [], $id) {}
  8. }

UserRepository 中登录方法:

  1. <?php
  2. namespace app\Repository\admin;
  3. use app\Model\admin\UserModel;
  4. class UserRepository
  5. {
  6. public function login($username, $password)
  7. {
  8. // 验证信息
  9. $user = app(UserModel)->getUser(['username' => $username, 'password' => $password]);
  10. if (!$user) return arrayFailed('login failed');
  11. // 登录成功后续操作
  12. app(UserModel)->update(['last_login_time' => time()], $user->id);
  13. }
  14. }

UserController 中使用 UserRepository 中的 login 方法:

  1. <?php
  2. namespace app\Repository\api;
  3. use think\Request;
  4. use app\Model\admin\UserRepository;
  5. class UserController
  6. {
  7. public function login(Request $request)
  8. {
  9. $res = app(UserRepository::class)->login($request->username, $request->password);
  10. }
  11. }

上面两个示例简单展示了在 Repository 中,处理结果数据与操作业务逻辑。这里也建议项目中加入 Repositoy 层,在保持代码整洁的同时,也有灵活的扩展性。