Base.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <?php
  2. namespace common\base\models;
  3. use common\components\util;
  4. use yii\db\ActiveRecord;
  5. class Base extends ActiveRecord
  6. {
  7. /**
  8. * 获取当前模型实例
  9. * @return static
  10. */
  11. public function getModel()
  12. {
  13. $self = get_called_class();
  14. return new $self;
  15. }
  16. /**
  17. * 添加数据
  18. * @param array $data 数据数组
  19. * @param bool $returnObject 是否返回对象,true返回模型对象,false返回数组
  20. * @return $this|array
  21. * @throws \Exception
  22. */
  23. public function add($data, $returnObject = false)
  24. {
  25. $model = $this->getModel();
  26. $attributes = $model->attributes;
  27. $fields = array_keys($attributes);
  28. foreach ($fields as $key) {
  29. if (isset($data[$key])) {
  30. $model->$key = $data[$key];
  31. }
  32. }
  33. if (!$model->validate()) {
  34. // 验证失败: $errors 是一个包含错误信息的数组
  35. \Yii::error(static::tableName() . ' -- model validate errors: ' . json_encode($model->errors));
  36. util::fail('输入数据验证失败');
  37. }
  38. // 保存数据并检查结果
  39. if (!$model->save()) {
  40. $errors = $model->errors;
  41. \Yii::error(static::tableName() . ' -- save failed: ' . json_encode($errors));
  42. throw new \Exception('数据保存失败: ' . json_encode($errors));
  43. }
  44. return $returnObject ? $model : $model->attributes;
  45. }
  46. /**
  47. * 批量添加
  48. * @param array $data 二维数组 [['name'=>'a'], ['name'=>'b']]
  49. * @return void
  50. */
  51. public function batchAdd($data)
  52. {
  53. $model = $this->getModel();
  54. foreach ($data as $attributes) {
  55. $newModel = clone $model;
  56. // false 不检测字段安全 true 需要在model设置rules
  57. $newModel->setAttributes($attributes, false);
  58. $newModel->save();
  59. }
  60. }
  61. /**
  62. * 获取表的所有字段名
  63. * @return array
  64. */
  65. public function getFields()
  66. {
  67. $model = $this->getModel();
  68. $attributes = $model->attributes;
  69. return array_keys($attributes);
  70. }
  71. /**
  72. * 根据主键ID删除一条记录
  73. * @param int|string $id 主键ID
  74. * @return int|false 删除的行数,失败返回false
  75. * @throws \Throwable
  76. * @throws \yii\db\StaleObjectException
  77. */
  78. public function deleteById($id)
  79. {
  80. $model = $this->getModel();
  81. return $model::findOne($id)->delete();
  82. }
  83. /**
  84. * 根据多个主键ID批量删除
  85. * @param array $ids 主键ID数组
  86. * @return int 删除的行数
  87. */
  88. public function deleteByIds($ids)
  89. {
  90. $model = $this->getModel();
  91. return $model::deleteAll(['id' => $ids]);
  92. }
  93. /**
  94. * 根据条件删除一条或多条记录
  95. * @param array $condition 查询条件
  96. * @return int 删除的行数
  97. */
  98. public function deleteByCondition($condition)
  99. {
  100. if (empty($condition)) {
  101. return 0;
  102. }
  103. $where = array();
  104. $variable = array();
  105. foreach ($condition as $key => $val) {
  106. $where[] = $key . '=:' . $key;
  107. $variable[':' . $key] = $val;
  108. }
  109. $whereString = implode(' and ', $where);
  110. $count = self::deleteAll($whereString, $variable);
  111. return $count;
  112. }
  113. /**
  114. * 根据主键ID更新一条记录
  115. * @param int|string $id 主键ID
  116. * @param array $data 更新的数据
  117. * @return array ['status' => bool, 'data' => array] status=true更新成功,false更新失败
  118. */
  119. public function updateById($id, $data)
  120. {
  121. $model = $this->getModel();
  122. $attributes = $model->attributes;
  123. $fields = array_keys($attributes);
  124. foreach ($data as $key => $val) {
  125. if (in_array($key, $fields) == false) {
  126. //删除表里不存在字段
  127. unset($data[$key]);
  128. }
  129. }
  130. $re = self::updateAll($data, 'id=:id', ['id' => $id]);
  131. if ($re == 1) {
  132. return ['status' => true, 'data' => $data];
  133. }
  134. return ['status' => false, 'data' => $data];
  135. }
  136. /**
  137. * 根据多个主键ID批量更新
  138. * @param array $ids 主键ID数组
  139. * @param array $data 更新的数据
  140. * @return int 更新的行数
  141. */
  142. public function updateByIds($ids, $data)
  143. {
  144. return self::updateAll($data, ['id' => $ids]);
  145. }
  146. /**
  147. * 根据条件更新一条或多条记录
  148. * @param array $condition 查询条件
  149. * @param array $data 更新的数据
  150. * @return int 更新的行数
  151. */
  152. public function updateByCondition($condition, $data)
  153. {
  154. $where = array();
  155. $variable = array();
  156. foreach ($condition as $key => $val) {
  157. $where[] = $key . '=:' . $key;
  158. $variable[':' . $key] = $val;
  159. }
  160. $whereString = implode(' and ', $where);
  161. $count = self::updateAll($data, $whereString, $variable);
  162. return $count;
  163. }
  164. /**
  165. * 根据主键ID查出一条记录
  166. * @param int|string $id 主键ID
  167. * @param bool $returnObject 是否返回对象
  168. * @param string|array $field 查询字段
  169. * @return array|ActiveRecord|null
  170. * @throws \Exception
  171. */
  172. public function getById($id, $returnObject = false, $field = '*')
  173. {
  174. $query = $this->conditionQuery(['id' => $id])->select($field);
  175. if ($returnObject == false) {
  176. return $query->asArray()->one();
  177. } else {
  178. return $query->one();
  179. }
  180. }
  181. /**
  182. * 根据条件查出一条记录
  183. * @param array $condition 查询条件
  184. * @param bool $returnObject 是否返回对象
  185. * @param string|array|bool $order 排序
  186. * @param string|array $field 查询字段
  187. * @return array|ActiveRecord|null
  188. * @throws \Exception
  189. */
  190. public function getByCondition($condition, $returnObject = false, $order = false, $field = '*')
  191. {
  192. $query = $this->conditionQuery($condition)->select($field);
  193. if (isset($order)) {
  194. $query->orderBy($order);
  195. }
  196. return $returnObject == true ? $query->one() : $query->asArray()->one();
  197. }
  198. /**
  199. * 获取第一条记录 (通常用于获取任意一条或结合排序获取特定一条)
  200. * @param bool $returnObject 是否返回对象
  201. * @param string|array|bool $order 排序
  202. * @param string|array $field 查询字段
  203. * @return array|ActiveRecord|null
  204. * @throws \Exception
  205. */
  206. public function getOne($returnObject = false, $order = false, $field = '*')
  207. {
  208. $query = $this->conditionQuery([])->select($field);
  209. if (isset($order)) {
  210. $query->orderBy($order);
  211. }
  212. return $returnObject == true ? $query->one() : $query->asArray()->one();
  213. }
  214. /**
  215. * 构建查询条件对象
  216. * 支持查询条件包括:
  217. * $condition = [
  218. * 'name' => 'john', // 等于
  219. * 'id>' => 3, // 大于
  220. * 'id<' => 10, // 小于
  221. * 'id>=' => 3, // 大于等于
  222. * 'id<=' => 10, // 小于等于
  223. * 'id!=' => -1, // 不等于
  224. * 'id' => ['in', [10,11,12]], // IN
  225. * 'id' => ['not in', [10,11,12]], // NOT IN
  226. * 'age' => ['between', [20,30]], // BETWEEN
  227. * 'name' => ['like', 'Jack'] // LIKE
  228. * ];
  229. * @param array $condition 查询条件数组
  230. * @return \yii\db\ActiveQuery
  231. * @throws \Exception
  232. */
  233. public function conditionQuery($condition = [])
  234. {
  235. $whereNum = 0;
  236. $query = self::find();
  237. if (!empty($condition)) {
  238. foreach ($condition as $key => $val) {
  239. $param = [$key => $val];
  240. if (strstr($key, '!=')) {
  241. //不等于
  242. $pos = strpos($key, '!=');
  243. $currentKey = substr($key, 0, $pos);
  244. $param = ['!=', $currentKey, $val];
  245. } elseif (strstr($key, '>=')) {
  246. //大于等于
  247. $pos = strpos($key, '>=');
  248. $currentKey = substr($key, 0, $pos);
  249. $param = ['>=', $currentKey, $val];
  250. } elseif (strstr($key, '<=')) {
  251. //小于等于
  252. $pos = strpos($key, '<=');
  253. $currentKey = substr($key, 0, $pos);
  254. $param = ['<=', $currentKey, $val];
  255. } elseif (strstr($key, '>')) {
  256. //大于
  257. $pos = strpos($key, '>');
  258. $currentKey = substr($key, 0, $pos);
  259. $param = ['>', $currentKey, $val];
  260. } elseif (strstr($key, '<')) {
  261. //小于
  262. $pos = strpos($key, '<');
  263. $currentKey = substr($key, 0, $pos);
  264. $param = ['<', $currentKey, $val];
  265. } elseif (is_array($val)) {
  266. if (count($val) != 2) {
  267. util::fail('参数不至2个,非法查询方式:' . json_encode($condition));
  268. }
  269. if ($val[0] == 'in') {
  270. $param = ['in', $key, $val[1]];
  271. } elseif ($val[0] == 'not in') {
  272. $param = ['not in', $key, $val[1]];
  273. } elseif ($val[0] == 'between') {
  274. $param = ['between', $key, $val[1][0], $val[1][1]];
  275. } elseif ($val[0] == 'like') {
  276. $param = ['like', $key, $val[1]];
  277. } else {
  278. util::fail('非法查询方式:' . json_encode($condition));
  279. }
  280. } else {
  281. }
  282. if ($whereNum == 0) {
  283. $query->where($param);
  284. } else {
  285. $query->andWhere($param);
  286. }
  287. $whereNum++;
  288. }
  289. }
  290. return $query;
  291. }
  292. /**
  293. * 判断数据是否存在
  294. * @param array $condition 查询条件
  295. * @return bool
  296. * @throws \Exception
  297. */
  298. public function exists($condition)
  299. {
  300. return $this->conditionQuery($condition)->exists();
  301. }
  302. /**
  303. * 根据条件查出多条记录
  304. * @param array $condition 查询条件
  305. * @param string|array|null $order 排序
  306. * @param string|array $field 查询字段
  307. * @param string|callable|null $indexBy 索引字段
  308. * @param bool $returnObject 是否返回对象
  309. * @return array|ActiveRecord[]
  310. * @throws \Exception
  311. */
  312. public function getAllByCondition($condition, $order = null, $field, $indexBy = null, $returnObject = false)
  313. {
  314. $query = $this->conditionQuery($condition)->select($field);
  315. if (isset($indexBy)) {
  316. $query->indexBy($indexBy);
  317. }
  318. if (isset($order)) {
  319. $query->orderBy($order);
  320. }
  321. if ($returnObject == false) {
  322. return $query->asArray()->all();
  323. } else {
  324. return $query->all();
  325. }
  326. }
  327. /**
  328. * 根据多个主键ID查询多条记录
  329. * @param array $ids 主键ID数组
  330. * @param string|array|null $order 排序
  331. * @param string|callable|null $indexBy 索引字段
  332. * @param string|array $field 查询字段
  333. * @return array
  334. * @throws \Exception
  335. */
  336. public function getByIds($ids, $order = null, $indexBy = null, $field = '*')
  337. {
  338. $data = [];
  339. if (empty($ids)) {
  340. return $data;
  341. }
  342. $query = $this->conditionQuery(['id' => ['in', $ids]])->select($field);
  343. if (isset($indexBy)) {
  344. $query->indexBy($indexBy);
  345. }
  346. if (!empty($order)) {
  347. $query->order($order);
  348. }
  349. $data = $query->asArray()->all();
  350. return $data;
  351. }
  352. /**
  353. * 根据条件获取记录数量
  354. * @param array $condition 查询条件
  355. * @return int|string
  356. * @throws \Exception
  357. */
  358. public function getCount($condition)
  359. {
  360. return $this->conditionQuery($condition)->count();
  361. }
  362. /**
  363. * 分页查询列表
  364. * @param string|array $field 查询字段
  365. * @param array $where 查询条件
  366. * @param int $page 当前页码
  367. * @param int $pageSize 每页数量
  368. * @param string|array $order 排序
  369. * @param string|array $with 关联查询
  370. * @return array ['totalNum' => int, 'totalPage' => int, 'moreData' => int, 'list' => array]
  371. * @throws \Exception
  372. */
  373. public function getList($field, $where, $page, $pageSize, $order = '', $with = '')
  374. {
  375. $offset = ($page - 1) * $pageSize;
  376. $query = $this->conditionQuery($where)->select($field);
  377. $clone = clone $query;
  378. $count = $clone->count();
  379. $totalPage = ceil($count / $pageSize);
  380. $data['totalNum'] = $count;
  381. $data['totalPage'] = $totalPage;//总共页数
  382. $data['moreData'] = $totalPage > $page ? 1 : 0;//是否还有更多数据
  383. if (!empty($order)) {
  384. $query->orderBy($order);
  385. }
  386. if (!empty($with)) {
  387. $query->with($with);
  388. }
  389. $list = $query->offset($offset)->limit($pageSize)->asArray()->all();
  390. $data['list'] = $list;//数据
  391. return $data;
  392. }
  393. /**
  394. * 查询全部列表 (不分页)
  395. * @param string|array $field 查询字段
  396. * @param array $where 查询条件
  397. * @param string|array $order 排序
  398. * @param string|array $with 关联查询
  399. * @return array
  400. * @throws \Exception
  401. */
  402. public function getAllList($field, $where, $order = '', $with = '')
  403. {
  404. $query = $this->conditionQuery($where)->select($field);
  405. if (!empty($order)) {
  406. $query->orderBy($order);
  407. }
  408. if (!empty($with)) {
  409. $query->with($with);
  410. }
  411. $list = $query->asArray()->all();
  412. return $list;
  413. }
  414. /**
  415. * 查询指定条数的列表
  416. * @param string|array $field 查询字段
  417. * @param array $where 查询条件
  418. * @param int $limit 限制条数
  419. * @param string|array $order 排序
  420. * @param string|array $with 关联查询
  421. * @return array
  422. * @throws \Exception
  423. */
  424. public function getLimitList($field, $where, $limit, $order = '', $with = '')
  425. {
  426. $offset = 0;
  427. $query = $this->conditionQuery($where)->select($field);
  428. if (!empty($order)) {
  429. $query->orderBy($order);
  430. }
  431. if (!empty($with)) {
  432. $query->with($with);
  433. }
  434. $list = $query->offset($offset)->limit($limit)->asArray()->all();
  435. return $list;
  436. }
  437. /**
  438. * 更新计数器 (原子操作)
  439. * @param array $counters 更新的计数器数组,例如 ['view_count' => 1] 表示加1,['view_count' => -1] 表示减1
  440. * @param array $condition 更新条件
  441. * @param array $params 绑定参数
  442. * @return int 更新行数
  443. */
  444. public function counters($counters, $condition, $params = [])
  445. {
  446. return self::updateAllCounters($counters, $condition, $params);
  447. }
  448. /**
  449. * 根据主键获取记录并锁定 (SELECT FOR UPDATE)
  450. * @param int|string $id 主键ID
  451. * @param string|array $field 查询字段
  452. * @return array|ActiveRecord|null
  453. */
  454. public function getLockById($id, $field = '*')
  455. {
  456. return self::findBySql('select ' . $field . ' from ' . static::tableName() . ' where id = :id for update', ['id' => $id])->one();
  457. }
  458. /**
  459. * 求和
  460. * @param array $condition 查询条件
  461. * @param string $field 求和字段
  462. * @return mixed
  463. * @throws \Exception
  464. */
  465. public function sum($condition, $field)
  466. {
  467. return $this->conditionQuery($condition)->sum($field);
  468. }
  469. }