PHP MVC 使用习惯

时间:2020-04-08 标签: PHP

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 层,在保持代码整洁的同时,也有灵活的扩展性。

© 2020 Lh1010 - 豫ICP备16115435号-1