关于Yii2基础controller和model的封装

如题,在实战项目中我们我们经常会要使用相同的逻辑,比如post/get获取参数,接口返回、参数校验等,因此可以将其封装起来调用。
这里分为根目录下的控制器controllers和处理数据库的models两个文件,其他业务逻辑放在modules模块中

一、根目录下controllers

// BaseController.php
<?php
namespace app\controllers;
use yii\web\{Controlle, IdentityInterface, Response};
use Yii;

// 继承 yii\web\controller, 其他controller则继承BaseController
class BaseController extends Controller
{
  /**
   * 错误码
   */
  protected $code = '';

  /**
   * 错误消息
   */
  protected $msg = 'success';

  /**
   * 响应报文
   */
  protected $rspData = [];

  /**
   * 模型
   */
  protected $model = null;

  /**
   * 路由
   */
  protected $route;

  public function __construct($id, $module, $config = [])
  {
    $this->route = Yii::$app->requestedRoute;
    Yii::info(json_encode($this->request(), JSON_UNESCAPED_SLASHES), "[ERQUEST BODY] $this->route");

    parent::__construct($id, $module, $config);
  }

  /**
   * 设置拦截器
   */
  public function behaviors(): array
  {
    return [];
  }

  public function init()
  {
    parent::init();
  }

  /**
   * 获取get参数
   */
  protected function get($key = '')
  {
    $get = $key ? Yii::$app->request->get($key) : Yii::$app->request->get();
    return $get;
  }

  /**
   * 获取 post 参数
   */
  protected function post($key = '')
  {
    $post = $key ? Yii::$app->request->post($key) : Yii::$app->request->post();
    return $post;
  }

  /**
   * 获取 get、post 参数
   */
  protected function request($key = '')
  {
    $get = $this->get($key);
    $post = $this->post($key);
    if (is_array($get) && is_array($post)) {
      return array_merge($get, $post);
    }

    return $post ? $post : ($get ?: null);
  }

  /**
   * 返回当前用户
   */
  public function getUserIdentity(): ?IdentityInterface
  {
    return Yii::$app->getUser()->identity;
  }

  /**
   * 前置操作
   */
  public function beforeAction($action): bool
  {
    $params = $this->post();

    /**
     * 分页、排序、参数处理
     */
    if ($this->model && !empty($params['page'])) {
      $page = intval($params['page']);
      if ($page < 1) {
        $page = 1;
      }
      $this->model->page = $page;
    }

    if ($this->model && !empty($params['pageSize'])) {
      $pageSize = Intval($params['pageSize']);
      $this->model->pageSize = $pageSize;
    }

    if ($this->model && !empty($params['_sorting'])) {
      $sorting = [];
      if (!is_array($params['_sorting'])) {
        $params['_sorting'] = json_decode($params['_sorting'], true);
      }

      foreach ($params['_sorting'] as $item) {
        $sorting[] = $item['field'] . ' ' . $item['type'];
      }
      $this->model->$sorting = implode(',', $sorting);
    }

    return parent::beforeAction($action);
  }

  /**
   * 判断是否是get方法
   */
  protected function isGet()
  {
    return Yii::$app->request->isGet;
  }

  /**
   * 判断是否是post方法
   */
  protected function isPost()
  {
    return Yii::$app->request->isPost;
  }

  /**
   * 组装JSON格式响应
   *
   * @param array $data
   * @return Response
   */
  public function asJson($data = []): Response
  {
    return parent::asJson(['code' => $this->code, 'msg' => $this->msg, 'data' => $data]);
  }

  protected function isAjax()
  {
    return Yii::$app->request->isAjax;
  }

  protected function littleToHump($word): string
  {
    $separator = '_';
    $word = $separator . str_replace($separator, '', $word);
    return ltrim(str_replace(' ', '', ucwords($word)), $separator);
  }

  /**
   * 响应数据
   */
  protected function response($data = []): array
  {
    Yii::$app->response->format = Response::FORMAT_JSON;

    if ($this->code) {
      $rsp = [
        'code' => $this->code,
        'msg' => $this->msg,
        'data' => $this->rspData ?: $data
      ];
    } else {
      $rsp = [
        'code' => '00000',
        'msg' => $this->msg ?: 'success',
        'data' => $this->rspData ?: $data
      ];
    }

    return $rsp;
  }

  /**
   * 后置操作
   */
  public function afterAction($action, $result)
  {
    return parent::afterAction($action, $result);
  }

  /**
   * 验参
   */
  public function paramsValidate(array $params, array $fieldRules, string $translator = 'default', string $tag = ''): bool
  {
    // field_validator 来自web/index.php中全局注册的components/helper/function.php
    $res = field_validator($params, $fieldRules, $translator, $tag);

    if (!empty($res)) {
      // 将校验参数的结果赋值给code, msg
      [$this->code, $this->msg] = $res;
      return false;
    }
    return true;
  }
}

?>

二、根目录下models

// BaseModel.php
// 继承yii\db\ActiveRecord, 增删改查,操作数据库
<?php
namespace app\models;

use yii\db\{ActiveRecord, ActiveQuery, Connection, Exception};
use Yii;

abstract class BaseModel extends ActiveRecord
{
  public $page = 1; // 查询limit页码
  public $pageSize = 20;
  protected static $insertId = 0; // 插入数据的的ID

  /**
   * 调用父依赖构造函数
   *
   * @param array $config
   */
  public function __construct($config = [])
  {
    parent::__construct($config);
  }

  /**
   * 数据库实例
   * @return Connection interface
   */
  public function dbInstance(): Connection
  {
    $db = static::getDb(); // ActiveRecord方法,连接db
    if ($db) {
      return $db;
    }
    return Yii::$app->db; // 默认全局db
  }

  /**
   * 查询对象
   * @return ActiveQuery interface
   */
  public function query(): ActiveQuery
  {
    return self::find(); // ActiveRecord方法,查询
  }

  /**
   * 组装查询对象
   * 
   * @param array $conditions 条件集合数组
   * @param array $fields 查询字段
   * @param array $expression 条件连接符
   * @param array $table 指定数据表
   * 
   * @return ActiveQuery interface
   */
  public function queryDbAll(array $conditions = [], string $fields = '*', string $expression = 'and', string $table = ''): ActiveQuery
  {
    // 兼容一维数组
    if (
      empty(array_filter($conditions, function ($v, $k) {
        return is_array($v) && is_numeric($k);
      }, ARRAY_FILTER_USE_BOTH))
    ) {
      $conditions = [$conditions];
    }

    if (empty($table)) {
      $query = self::find()->select($fields);
    } else {
      $query = self::find()->from($table)->select($fields);
    }

    // array_filter默认去除false元素
    foreach (array_filter($conditions) as $k => $v) {
      if ($k === 0) {
        $query->where($v);
        continue;
      }

      switch ($expression) {
        case 'or':
          $query->orWhere($v);
        case 'and':
        default:
          $query->andWhere($v);
      }
    }

    // echo $query -> createCommand() -> getRawSql();
    return $query;
  }

  /**
   * 获取单条记录
   */
  public function getDbOne(array $conditions = [], string $fields = '*', string $expression = 'and'): ?array
  {
    // 兼容一维数组
    if (
      empty(array_filter($conditions, function ($v, $k) {
        return is_array($v) && is_numeric($k);
      }, ARRAY_FILTER_USE_BOTH))
    ) {
      $conditions = [$conditions];
    }

    $query = self::find()->select($fields);

    foreach (array_filter($conditions) as $k => $v) {
      if ($k === 0) {
        $query->where($v);
        continue;
      }

      switch ($expression) {
        case 'or':
          $query->orWhere($v);
          break;
        case 'and':
        default:
          $query->andWhere($v);
          break;
      }
    }

    if (in_array('id', static::primaryKey())) {
      $query->orderBy(['id' => SORT_DESC]);
    }

    $res = $query->asArray()->one();

    if (!empty($res)) {
      camel_snake($res);
    }

    return $res;
  }

  /**
   * 获取全部记录
   * @param array $conditions 表示查询条件,默认无条件查询
   * @param string $fields 表示返回的字段,默认全部返回,消耗接口流量宽带
   * @param array $order 表示排序,默认id降序
   * @param boolean $limit 表示数据条数,默认取全部
   * @param array $groupBy 表示列中同值分组,默认不分组
   * @param string $expression 表示条件关系,默认and
   */
  public function getDbAll(array $conditions = [], string $fields = '*', array $order = ['id' => SORT_ASC], bool $limit = false, array $groupBy = [], string $expression = 'and'): array
  {
    /**
     * 兼容一维数组,最终转出二维数组
     * array_filter() ARRAY_FILTER_USE_BOTH表示回调可以接收两个参数 $v, $k
     * 当前array_filter表示过滤获取二维数组,如果得到空数组,则表示非二维数组,一维数组需要转出二维数组
     */
    if (
      empty(array_filter($conditions, function ($v, $k) {
        return is_array($v) && is_numeric($k);
      }, ARRAY_FILTER_USE_BOTH))
    ) {
      $conditions = [$conditions];
    }

    $query = self::find()->select($fields);

    foreach (array_filter($conditions) as $k => $v) {
      if ($k === 0) {
        $query->where($v);
        continue;
      }

      switch ($expression) {
        case 'or':
          $query->orWhere($v);
          break;
        case 'and':
        default:
          $query->andWhere($v);
      }
    }

    // dd(11, $conditions, $fields, $query);
    if (!empty($groupBy)) {
      $query->groupBy($groupBy);
    }
    if (!empty($order)) {
      $query->orderBy($order);
    }

    if ($limit) {
      $query->limit($this->pageSize)->offset(bcmul($this->pageSize, bcsub($this->page, 1)));
    }

    $res = $query->asArray()->all();

    array_walk($res, function (&$v) {
      if (!empty($v)) {
        camel_snake($v);
      }
    });

    return $res;
  }

  /**
   * 获取记录行
   */
  public function getCount(array $conditions = [], string $expression = 'and'): int
  {
    // 兼容一维数组
    if (
      empty(array_filter($conditions, function ($v, $k) {
        return is_array($v) && is_numeric($k);
      }, ARRAY_FILTER_USE_BOTH))
    ) {
      $conditions = [$conditions];
    }

    $query = self::find();

    foreach (array_filter($conditions) as $k => $v) {
      if ($k === 0) {
        $query->where($v);
        continue;
      }

      switch ($expression) {
        case 'or':
          $query->orWhere($v);
          break;
        case 'and':
        default:
          $query->addWhere($v);
      }
    }
    return $query->count();
  }

  /**
   * 添加记录
   */
  public function create(array $data): int
  {
    $rows = $this->dbInstance()->createCommand()->insert(static::tableName(), $data)->execute();
    // 记录自增ID
    self::$insertId = $this->dbInstance()->getLastInsertID();
    return $rows;
  }

  /**
   * 批量添加
   */
  public function batchCreate(array $fields, array $data): int
  {
    if (empty($fields) || empty($data)) {
      throw new Exception('Missing batch fields or data');
    }

    $rows = $this->dbInstance()->createCommand()->batchInsert(
      static::tableName(),
      $fields,
      $data
    )->execute();

    self::$insertId = $this->dbInstance()->getLastInsertID();
    return $rows;
  }

  /**
   * 获取插入的自增ID
   */
  public function getInsertId(): int
  {
    return self::$insertId;
  }

  /**
   * 更改记录,
   *  $data 新的数据
   *  $conditions 查询条件的集合,如['id' => 'id', 'sex' => 'man']
   */
  public function updateByCondition(array $data, array $conditions): int
  {
    if (empty($data) || empty($conditions)) {
      throw new Exception('Missing data or conditions');
    }

    return $this->dbInstance()->createCommand()->update(
      static::tableName(),
      $data,
      $conditions
    )->execute();
  }

  /**
   * 指定主键删除记录
   */
  public function deleteById(int $id): void
  {
    if (empty($id)) {
      throw new Exception('Missing primary key');
    }

    self::findOne($id)->delete();
  }


  /**
   * 指定删除记录
   */
  public function deleteData(array $params): void
  {
    if (empty($params)) {
      throw new Exception('Missing primary key');
    }

    self::findOne($params)->delete();
  }

  /**
   * 判断数据表是否存在
   */
  public function tableExist(string $tableName): bool
  {
    return !empty($this->dbInstance()->getTableSchema($tableName));
  }
}

?>

你可能感兴趣的:(数据库,php,yii)