| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- <?php
- namespace common\base\models;
- use common\components\util;
- use Yii;
- use yii\db\ActiveRecord;
- class Base extends ActiveRecord
- {
- /**
- * 获取当前模型实例
- * @return static
- */
- public function getModel()
- {
- $self = get_called_class();
- return new $self;
- }
- /**
- * 添加数据
- * @param array $data 数据数组
- * @param bool $returnObject 是否返回对象,true返回模型对象,false返回数组
- * @return $this|array
- * @throws \Exception
- */
- public function add($data, $returnObject = false)
- {
- $model = $this->getModel();
- $attributes = $model->attributes;
- $fields = array_keys($attributes);
- foreach ($fields as $key) {
- if (isset($data[$key])) {
- $model->$key = $data[$key];
- }
- }
- if (!$model->validate()) {
- // 验证失败: $errors 是一个包含错误信息的数组
- \Yii::error(static::tableName() . ' -- model validate errors: ' . json_encode($model->errors));
- util::fail('输入数据验证失败');
- }
- // 保存数据并检查结果
- if (!$model->save()) {
- $errors = $model->errors;
- \Yii::error(static::tableName() . ' -- save failed: ' . json_encode($errors));
- throw new \Exception('数据保存失败: ' . json_encode($errors));
- }
- return $returnObject ? $model : $model->attributes;
- }
- /**
- * 批量添加
- * @param array $data 二维数组 [['name'=>'a'], ['name'=>'b']]
- * @return void
- */
- public function batchAdd($data)
- {
- $model = $this->getModel();
- foreach ($data as $attributes) {
- $newModel = clone $model;
- // false 不检测字段安全 true 需要在model设置rules
- $newModel->setAttributes($attributes, false);
- $newModel->save();
- }
- }
- /**
- * 获取表的所有字段名
- * @return array
- */
- public function getFields()
- {
- $model = $this->getModel();
- $attributes = $model->attributes;
- return array_keys($attributes);
- }
- /**
- * 根据主键ID删除一条记录
- * @param int|string $id 主键ID
- * @return int|false 删除的行数,失败返回false
- * @throws \Throwable
- * @throws \yii\db\StaleObjectException
- */
- public function deleteById($id)
- {
- $model = $this->getModel();
- return $model::findOne($id)->delete();
- }
- /**
- * 根据多个主键ID批量删除
- * @param array $ids 主键ID数组
- * @return int 删除的行数
- */
- public function deleteByIds($ids)
- {
- $model = $this->getModel();
- return $model::deleteAll(['id' => $ids]);
- }
- /**
- * 根据条件删除一条或多条记录
- * @param array $condition 查询条件
- * @return int 删除的行数
- */
- public function deleteByCondition($condition)
- {
- if (empty($condition)) {
- return 0;
- }
- $where = array();
- $variable = array();
- foreach ($condition as $key => $val) {
- $where[] = $key . '=:' . $key;
- $variable[':' . $key] = $val;
- }
- $whereString = implode(' and ', $where);
- $count = self::deleteAll($whereString, $variable);
- return $count;
- }
- /**
- * 根据主键ID更新一条记录
- * @param int|string $id 主键ID
- * @param array $data 更新的数据
- * @return array ['status' => bool, 'data' => array] status=true更新成功,false更新失败
- */
- public function updateById($id, $data)
- {
- $model = $this->getModel();
- $attributes = $model->attributes;
- $fields = array_keys($attributes);
- foreach ($data as $key => $val) {
- if (in_array($key, $fields) == false) {
- //删除表里不存在字段
- unset($data[$key]);
- }
- }
- $re = self::updateAll($data, 'id=:id', ['id' => $id]);
- if ($re == 1) {
- return ['status' => true, 'data' => $data];
- }
- return ['status' => false, 'data' => $data];
- }
- /**
- * 根据多个主键ID批量更新
- * @param array $ids 主键ID数组
- * @param array $data 更新的数据
- * @return int 更新的行数
- */
- public function updateByIds($ids, $data)
- {
- return self::updateAll($data, ['id' => $ids]);
- }
- /**
- * 根据条件更新一条或多条记录
- * @param array $condition 查询条件
- * @param array $data 更新的数据
- * @return int 更新的行数
- */
- public function updateByCondition($condition, $data)
- {
- $where = array();
- $variable = array();
- foreach ($condition as $key => $val) {
- $where[] = $key . '=:' . $key;
- $variable[':' . $key] = $val;
- }
- $whereString = implode(' and ', $where);
- $count = self::updateAll($data, $whereString, $variable);
- return $count;
- }
- /**
- * 根据主键ID查出一条记录
- * @param int|string $id 主键ID
- * @param bool $returnObject 是否返回对象
- * @param string|array $field 查询字段
- * @param bool $reverseExclude 是否反向排除字段(传入的字段不查询,其他字段都查询出来),传 true 则反向排除,false 则正向排除,默认 false
- * @return array|ActiveRecord|null
- * @throws \Exception
- */
- public function getById($id, $returnObject = false, $field = '*', $reverseExclude = false)
- {
- $selectField = '*';
- if (!empty($field) && $field !== '*' && $reverseExclude == true) {
- $excludeFields = is_array($field) ? $field : array_map('trim', explode(',', $field));
- $allFields = $this->getFields();
- $selectField = array_values(array_diff($allFields, $excludeFields));
- if (empty($selectField)) {
- Yii::error('getById: selectField is empty');
- return null;
- }
- } else if (!empty($field) && $field !== '*' && $reverseExclude == false) {
- $selectField = $field;
- }
- $query = $this->conditionQuery(['id' => $id])->select($selectField);
- if ($returnObject == false) {
- return $query->asArray()->one();
- } else {
- return $query->one();
- }
- }
- /**
- * 根据条件查出一条记录
- * @param array $condition 查询条件
- * @param bool $returnObject 是否返回对象
- * @param string|array|bool $order 排序
- * @param string|array $field 查询字段
- * @return array|ActiveRecord|null
- * @throws \Exception
- */
- public function getByCondition($condition, $returnObject = false, $order = false, $field = '*')
- {
- $query = $this->conditionQuery($condition)->select($field);
- if (isset($order)) {
- $query->orderBy($order);
- }
- return $returnObject == true ? $query->one() : $query->asArray()->one();
- }
- /**
- * 获取第一条记录 (通常用于获取任意一条或结合排序获取特定一条)
- * @param bool $returnObject 是否返回对象
- * @param string|array|bool $order 排序
- * @param string|array $field 查询字段
- * @return array|ActiveRecord|null
- * @throws \Exception
- */
- public function getOne($returnObject = false, $order = false, $field = '*')
- {
- $query = $this->conditionQuery([])->select($field);
- if (isset($order)) {
- $query->orderBy($order);
- }
- return $returnObject == true ? $query->one() : $query->asArray()->one();
- }
- /**
- * 构建查询条件对象
- * 支持查询条件包括:
- * $condition = [
- * 'name' => 'john', // 等于
- * 'id>' => 3, // 大于
- * 'id<' => 10, // 小于
- * 'id>=' => 3, // 大于等于
- * 'id<=' => 10, // 小于等于
- * 'id!=' => -1, // 不等于
- * 'id' => ['in', [10,11,12]], // IN
- * 'id' => ['not in', [10,11,12]], // NOT IN
- * 'age' => ['between', [20,30]], // BETWEEN
- * 'name' => ['like', 'Jack'] // LIKE
- * ];
- * @param array $condition 查询条件数组
- * @return \yii\db\ActiveQuery
- * @throws \Exception
- */
- public function conditionQuery($condition = [])
- {
- $whereNum = 0;
- $query = self::find();
- if (!empty($condition)) {
- foreach ($condition as $key => $val) {
- $param = [$key => $val];
- if (strstr($key, '!=')) {
- //不等于
- $pos = strpos($key, '!=');
- $currentKey = substr($key, 0, $pos);
- $param = ['!=', $currentKey, $val];
- } elseif (strstr($key, '>=')) {
- //大于等于
- $pos = strpos($key, '>=');
- $currentKey = substr($key, 0, $pos);
- $param = ['>=', $currentKey, $val];
- } elseif (strstr($key, '<=')) {
- //小于等于
- $pos = strpos($key, '<=');
- $currentKey = substr($key, 0, $pos);
- $param = ['<=', $currentKey, $val];
- } elseif (strstr($key, '>')) {
- //大于
- $pos = strpos($key, '>');
- $currentKey = substr($key, 0, $pos);
- $param = ['>', $currentKey, $val];
- } elseif (strstr($key, '<')) {
- //小于
- $pos = strpos($key, '<');
- $currentKey = substr($key, 0, $pos);
- $param = ['<', $currentKey, $val];
- } elseif (is_array($val)) {
- if (count($val) != 2) {
- util::fail('参数不至2个,非法查询方式:' . json_encode($condition));
- }
- if ($val[0] == 'in') {
- $param = ['in', $key, $val[1]];
- } elseif ($val[0] == 'not in') {
- $param = ['not in', $key, $val[1]];
- } elseif ($val[0] == 'between') {
- $param = ['between', $key, $val[1][0], $val[1][1]];
- } elseif ($val[0] == 'like') {
- $param = ['like', $key, $val[1]];
- } else {
- util::fail('非法查询方式:' . json_encode($condition));
- }
- } else {
- }
- if ($whereNum == 0) {
- $query->where($param);
- } else {
- $query->andWhere($param);
- }
- $whereNum++;
- }
- }
- return $query;
- }
- /**
- * 判断数据是否存在
- * @param array $condition 查询条件
- * @return bool
- * @throws \Exception
- */
- public function exists($condition)
- {
- return $this->conditionQuery($condition)->exists();
- }
- /**
- * 根据条件查出多条记录
- * @param array $condition 查询条件
- * @param string|array|null $order 排序
- * @param string|array $field 查询字段
- * @param string|callable|null $indexBy 索引字段
- * @param bool $returnObject 是否返回对象
- * @return array|ActiveRecord[]
- * @throws \Exception
- */
- public function getAllByCondition($condition, $order = null, $field, $indexBy = null, $returnObject = false)
- {
- $query = $this->conditionQuery($condition)->select($field);
- if (isset($indexBy)) {
- $query->indexBy($indexBy);
- }
- if (isset($order)) {
- $query->orderBy($order);
- }
- if ($returnObject == false) {
- return $query->asArray()->all();
- } else {
- return $query->all();
- }
- }
- /**
- * 根据多个主键ID查询多条记录
- * @param array $ids 主键ID数组
- * @param string|array|null $order 排序
- * @param string|callable|null $indexBy 索引字段
- * @param string|array $field 查询字段
- * @return array
- * @throws \Exception
- */
- public function getByIds($ids, $order = null, $indexBy = null, $field = '*')
- {
- $data = [];
- if (empty($ids)) {
- return $data;
- }
- $query = $this->conditionQuery(['id' => ['in', $ids]])->select($field);
- if (isset($indexBy)) {
- $query->indexBy($indexBy);
- }
- if (!empty($order)) {
- $query->order($order);
- }
- $data = $query->asArray()->all();
- return $data;
- }
- /**
- * 根据条件获取记录数量
- * @param array $condition 查询条件
- * @return int|string
- * @throws \Exception
- */
- public function getCount($condition)
- {
- return $this->conditionQuery($condition)->count();
- }
- /**
- * 分页查询列表
- * @param string|array $field 查询字段
- * @param array $where 查询条件
- * @param int $page 当前页码
- * @param int $pageSize 每页数量
- * @param string|array $order 排序
- * @param string|array $with 关联查询
- * @return array ['totalNum' => int, 'totalPage' => int, 'moreData' => int, 'list' => array]
- * @throws \Exception
- */
- public function getList($field, $where, $page, $pageSize, $order = '', $with = '')
- {
- $offset = ($page - 1) * $pageSize;
- $query = $this->conditionQuery($where)->select($field);
- $clone = clone $query;
- $count = $clone->count();
- $totalPage = ceil($count / $pageSize);
- $data['totalNum'] = $count;
- $data['totalPage'] = $totalPage;//总共页数
- $data['moreData'] = $totalPage > $page ? 1 : 0;//是否还有更多数据
- if (!empty($order)) {
- $query->orderBy($order);
- }
- if (!empty($with)) {
- $query->with($with);
- }
- $list = $query->offset($offset)->limit($pageSize)->asArray()->all();
- $data['list'] = $list;//数据
- return $data;
- }
- /**
- * 查询全部列表 (不分页)
- * @param string|array $field 查询字段
- * @param array $where 查询条件
- * @param string|array $order 排序
- * @param string|array $with 关联查询
- * @return array
- * @throws \Exception
- */
- public function getAllList($field, $where, $order = '', $with = '')
- {
- $query = $this->conditionQuery($where)->select($field);
- if (!empty($order)) {
- $query->orderBy($order);
- }
- if (!empty($with)) {
- $query->with($with);
- }
- $list = $query->asArray()->all();
- return $list;
- }
- /**
- * 查询指定条数的列表
- * @param string|array $field 查询字段
- * @param array $where 查询条件
- * @param int $limit 限制条数
- * @param string|array $order 排序
- * @param string|array $with 关联查询
- * @return array
- * @throws \Exception
- */
- public function getLimitList($field, $where, $limit, $order = '', $with = '')
- {
- $offset = 0;
- $query = $this->conditionQuery($where)->select($field);
- if (!empty($order)) {
- $query->orderBy($order);
- }
- if (!empty($with)) {
- $query->with($with);
- }
- $list = $query->offset($offset)->limit($limit)->asArray()->all();
- return $list;
- }
- /**
- * 更新计数器 (原子操作)
- * @param array $counters 更新的计数器数组,例如 ['view_count' => 1] 表示加1,['view_count' => -1] 表示减1
- * @param array $condition 更新条件
- * @param array $params 绑定参数
- * @return int 更新行数
- */
- public function counters($counters, $condition, $params = [])
- {
- return self::updateAllCounters($counters, $condition, $params);
- }
- /**
- * 根据主键获取记录并锁定 (SELECT FOR UPDATE)
- * @param int|string $id 主键ID
- * @param string|array $field 查询字段
- * @return array|ActiveRecord|null
- */
- public function getLockById($id, $field = '*')
- {
- return self::findBySql('select ' . $field . ' from ' . static::tableName() . ' where id = :id for update', ['id' => $id])->one();
- }
- /**
- * 求和
- * @param array $condition 查询条件
- * @param string $field 求和字段
- * @return mixed
- * @throws \Exception
- */
- public function sum($condition, $field)
- {
- return $this->conditionQuery($condition)->sum($field);
- }
- }
|