BaseActiveRecord.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. /**
  3. * @link:http://www.gdqijianshi.com/
  4. * @copyright: Copyright (c) 2020 广东七件事集团
  5. * Created by PhpStorm
  6. * Author: zal
  7. * Date: 2020-04-08
  8. * Time: 15:12
  9. */
  10. namespace common\models\base;
  11. use app\component\jobs\AdminActionJob;
  12. use app\forms\common\OperateModelForm;
  13. use app\helpers\ArrayHelper;
  14. use common\helpers\StringHelper;
  15. use common\models\common\BackendLog;
  16. use common\traits\ErrorTrait;
  17. use Yii;
  18. use yii\behaviors\TimestampBehavior;
  19. use yii\data\Pagination;
  20. use yii\db\ActiveQuery;
  21. use yii\db\ActiveRecord;
  22. use yii\db\Exception;
  23. use function EasyWeChat\Kernel\Support\get_client_ip;
  24. class BaseActiveRecord extends \yii\db\ActiveRecord
  25. {
  26. use ErrorTrait;
  27. protected static $_sql = [];
  28. protected static $_query = '';
  29. protected static $_params = [];
  30. /**
  31. * @return array
  32. */
  33. public function behaviors()
  34. {
  35. return [
  36. [
  37. 'class' => TimestampBehavior::class,
  38. 'attributes' => [
  39. ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
  40. ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
  41. ],
  42. ],
  43. ];
  44. }
  45. // /**
  46. // * @return BaseActiveQuery
  47. // */
  48. // public static function find()
  49. // {
  50. // return \Yii::createObject(ActiveQuery::class, [get_called_class()]);
  51. // }
  52. /**
  53. * 除去空参数
  54. * @Author bing
  55. * @DateTime 2021-12-21 15:23:24
  56. * @copyright: Copyright (c) 2020 广东七件事集团
  57. * @param [type] $params
  58. * @return array
  59. */
  60. public static function exceptNullVal($params){
  61. foreach($params as $key => $val){
  62. if($val === null) unset($params[$key]);
  63. }
  64. return $params;
  65. }
  66. /**
  67. * 统计
  68. * @Author bing
  69. * @DateTime 2020-10-27 15:23:39
  70. * @copyright: Copyright (c) 2020 广东七件事集团
  71. * @param string $where
  72. * @return void|mixed
  73. */
  74. public static function count($params,$limit = 0){
  75. $model = static::find();
  76. self::paramPack($params, $model);
  77. if($limit > 0) $model->limit($limit);
  78. self::$_sql[] = $model->createCommand()->getRawSql();
  79. return $model->count();
  80. }
  81. /**
  82. * 获取一个
  83. * @Author bing
  84. * @DateTime 2020-10-27 15:24:02
  85. * @copyright: Copyright (c) 2020 广东七件事集团
  86. * @param [type] $where
  87. * @param [type] $is_array
  88. * @param [type] $with
  89. * @param boolean $order
  90. * @param string $select
  91. * @return void|mixed
  92. */
  93. public static function getOne($where,$is_array=false,$with=[],$order=false,$select = '*',$index=''){
  94. $query = self::find();
  95. self::paramPack(['where'=>$where], $query);
  96. if($order) $query->orderBy($order);
  97. if($with) $query->with($with);
  98. $query->select($select);
  99. $query->asArray($is_array);
  100. if(!empty($index)) $query->indexBy($index);
  101. self::$_sql[] = $query->createCommand()->getRawSql();
  102. return $query->one();
  103. }
  104. /**
  105. * 获取一条关联查询
  106. * @Author bing
  107. * @DateTime 2020-10-27 15:24:36
  108. * @copyright: Copyright (c) 2020 广东七件事集团
  109. * @param array $params
  110. * @return void|mixed
  111. */
  112. public static function getUnionOne($params=[]){
  113. $params['limit'] = 1;
  114. $list = self::lists($params);
  115. if($list === false){
  116. return false;
  117. }
  118. return isset($list[0]) ? $list[0] : [];
  119. }
  120. /**
  121. * 获取数据列表总数
  122. * @Author bing
  123. * @DateTime 2020-10-27 15:25:34
  124. * @copyright: Copyright (c) 2020 广东七件事集团
  125. * @param array $params
  126. * @return void|mixed
  127. */
  128. public static function listCount($params=[]){
  129. $query = static::find();
  130. self::paramPack($params, $query);
  131. self::$_sql[] = $query->createCommand()->getRawSql();
  132. $count = $query->count();
  133. return $count;
  134. }
  135. /**
  136. * 获取数据列表
  137. * @Author bing
  138. * @DateTime 2020-10-27 15:25:51
  139. * @copyright: Copyright (c) 2020 广东七件事集团
  140. * @param array $params
  141. * @param boolean $is_array
  142. * @return mixed
  143. */
  144. public static function lists($params=[],$is_array=true){
  145. $list = [];
  146. $query = static::find();
  147. try{
  148. self::paramPack($params, $query);
  149. if(!empty($params['limit'])){
  150. $query->limit($params['limit']);
  151. }
  152. if(!empty($params['offset'])){
  153. $query->offset($params['offset']);
  154. }
  155. elseif(!empty($params['page']) && !empty($params['limit'])){
  156. $query->offset(($params['page']-1)*$params['limit']);
  157. }
  158. self::$_sql[] = $query->createCommand()->getRawSql();
  159. $list = $query->AsArray($is_array)->all();
  160. return $list;
  161. }catch (\Exception $e){
  162. var_dump($e->getMessage());
  163. self::$static_error = $e->getMessage();
  164. return false;
  165. }
  166. }
  167. /**
  168. * 通用分页列表数据集获取方法
  169. * @Author bing
  170. * @DateTime 2020-10-27 15:26:13
  171. * @copyright: Copyright (c) 2020 广东七件事集团
  172. * @param array $params 参数集合
  173. * @param boolean|int $count 总数 如果传进来,则不再执行查询总数 否则默认会查询
  174. * @param boolean $is_array
  175. * @return void|mixed
  176. */
  177. public static function listPage($params=[], $count=false,$is_array=true,$is_get_query=false){
  178. $return = ['list' => [], 'count' => 0];
  179. $query = static::find();
  180. try{
  181. self::paramPack($params, $query);
  182. $return['page'] = (Yii::$app->request->get('page') ?? Yii::$app->request->post('page')) ?? ($params['page'] ?? null) ?? 1;
  183. $return['page'] = $return['page'] > 0 ? $return['page'] : 1 ;
  184. $return['page_size'] = $params['limit'] ?? 20;
  185. if($count === false){
  186. //预加载分页优化
  187. $page_count_query = clone $query;
  188. $return['row_count'] = $page_count_query->count();
  189. //后面10页的数量
  190. $t = microtime(true);
  191. $offset_rows_count = $page_count_query->offset(($return['page'] - 1) * $return['page_size'])->limit(10 * $return['page_size'])->orderBy(null)->all();
  192. $offset_rows_count = count($offset_rows_count ?? []);
  193. if(YII_DEBUG) $return['sql'][] = self::$_sql[] = $page_count_query->createCommand()->getRawSql();
  194. unset($page_count_query);
  195. //前面的页码数量
  196. $prev_rows_count = $return['page_size'] * ($return['page'] - 1);
  197. $return['count'] = $offset_rows_count + $prev_rows_count;
  198. }else{
  199. $return['count'] = $count;
  200. }
  201. $pages = new Pagination(['totalCount' => $return['count'] ?? 1]);
  202. $pages->pageSizeParam = "limit";
  203. $pages->defaultPageSize = $return['page_size'];
  204. $pages->setPageSize($return['page_size']);
  205. $return['pagination'] = $pages;
  206. //总页数
  207. $return['page_count'] = (!empty($return['count'] ) && $return['count'] > 0) ? ceil($return['count'] / $return['page_size']) : 1;
  208. //边界处理
  209. if($return['page'] > $return['page_count']) $return['page'] = $return['page_count'];
  210. $query->limit($return['page_size']);
  211. $query->offset(($return['page'] - 1) * $return['page_size']);
  212. // $return['pagination'] = $pages;
  213. if($is_get_query) return $query;
  214. $return['list'] = $is_array ? $query->AsArray()->all() : $query->all();
  215. // echo '数据查询耗时'.(microtime(true) - $t).'s'.PHP_EOL;
  216. if(YII_DEBUG) $return['sql'][] = self::$_sql[] = $query->createCommand()->getRawSql();
  217. }catch (\Exception $exc){
  218. self::$static_error = $exc->getMessage();
  219. //$this->errors = $exc->getMessage();
  220. return false;
  221. }
  222. return $return;
  223. }
  224. /**
  225. * SQL组装
  226. * @Author bing
  227. * @DateTime 2020-10-27 15:27:08
  228. * @copyright: Copyright (c) 2020 广东七件事集团
  229. * @param array $params
  230. * @param [type] $query
  231. * @return void|mixed
  232. */
  233. public static function paramPack(array $params = [], &$query = null)
  234. {
  235. if(!empty($params['alias'])) $alias = $params['alias'];
  236. if(!empty($params['table'])){
  237. $table = isset($alias) ? ($params['table'] . ' ' . $alias) : $params['table'];
  238. }else{
  239. $table = isset($alias) ? (static::tableName() . ' ' . $alias) : static::tableName();
  240. }
  241. $query->from($table);
  242. if(!empty($params['where'])){
  243. if(is_array($params['where'])){
  244. foreach($params['where'] as $where){
  245. $query->andWhere($where);
  246. }
  247. }elseif(is_string($params['where'])){
  248. $query->andWhere($params['where']);
  249. }
  250. }
  251. if (!empty($params['and_where'])) {
  252. $query->where($params['and_where']);
  253. }
  254. if (!empty($params['or_where'])) {
  255. $query->orWhere($params['or_where']);
  256. }
  257. if(!empty($params['order'])) $query->orderBy($params['order']);
  258. if(!empty($params['join']) && is_array($params['join'])){
  259. foreach($params['join'] as $join){
  260. list($joinType,$joinTable,$joinOn) = $join;
  261. $query->join($joinType,$joinTable,$joinOn);
  262. }
  263. }
  264. if(!empty($params['with'])) $query->with($params['with']);
  265. if(!empty($params['joinWith'])) $query->joinWith($params['joinWith']);
  266. if(!empty($params['group'])) $query->groupBy($params['group']);
  267. if(!empty($params['having'])) $query->having($params['having']);
  268. if(!empty($params['select'])) $query->select($params['select']);
  269. if(!empty($params['index'])) $query->indexBy($params['index']);
  270. }
  271. /**
  272. * 获取错误信息
  273. * @Author bing
  274. * @DateTime 2020-10-16 15:01:06
  275. * @copyright: Copyright (c) 2020 广东七件事集团
  276. * @return mixed 错误信息
  277. */
  278. public static function getSql(){
  279. $sql = self::$_sql;
  280. if(empty($sql)) $sql = '';
  281. return $sql;
  282. }
  283. /**
  284. * 获取模型错误
  285. * @Author bing
  286. * @DateTime 2020-10-27 15:27:47
  287. * @copyright: Copyright (c) 2020 广东七件事集团
  288. * @param [type] $model
  289. * @return void|mixed
  290. */
  291. public function getErrorMessage($model = null){
  292. if (!$model) $model = $this;
  293. if(!empty($model->errors)){
  294. $msg = current($model->errors)[0];
  295. }else{
  296. $msg = self::$static_error ?? '未知错误';
  297. }
  298. return $msg;
  299. }
  300. /**
  301. * 保存生成操作日志
  302. * @Author: lun
  303. * @DateTime: 2023/4/24 0024 15:09
  304. * @Copyright: copyright (c) 2021 广东七件事集团
  305. * @param bool $insert
  306. * @param array $changedAttributes
  307. * @throws \yii\base\InvalidConfigException
  308. */
  309. public function afterSave($insert, $changedAttributes)
  310. {
  311. try {
  312. $formName = $this->formName();// 获取当前操作的模型
  313. // 后台用户登录信息
  314. if(!isset(Yii::$app->params['is_save_backend_log'])||Yii::$app->params['is_save_backend_log']==1){
  315. if(isset(Yii::$app->user)) {
  316. $admin = Yii::$app->user->identity;
  317. $ignore_model = ['BackendLog', 'AuthItemChild'];// 忽略的模型
  318. if ($admin && isset($admin['account']) && !in_array($formName, $ignore_model) && $changedAttributes) {
  319. $beforeUpdate = $changedAttributes;// 更新前的数据
  320. $afterUpdate = $this->attributes;// 更新后的数据
  321. $remark = '新增';
  322. if (isset($afterUpdate['updated_at']) && isset($afterUpdate['created_at']) && $afterUpdate['updated_at'] > $afterUpdate['created_at']) {
  323. $remark = "修改";
  324. }
  325. if (isset($afterUpdate['status'])) {
  326. if ($afterUpdate['status'] == 0) $remark = '禁用';
  327. if ($afterUpdate['status'] == -1) $remark = '删除';
  328. }
  329. // 获取修改过的数据
  330. $newBeforeUpdate = $newAfterUpdate = [];
  331. foreach ($beforeUpdate as $key => $item) {
  332. if (in_array($key, ['updated_at'])) continue;
  333. if ($item != $afterUpdate[$key]) {
  334. $newBeforeUpdate[$key] = $item;
  335. $newAfterUpdate[$key] = $afterUpdate[$key];
  336. }
  337. }
  338. // 新增操作日志
  339. if ($newBeforeUpdate || $newAfterUpdate) {
  340. $model = new BackendLog();
  341. $model->mall_id = $afterUpdate['mall_id'] ?? 0;
  342. $model->operate_id = $admin->id;
  343. $model->operate_name = $admin->account;
  344. $model->operate_ip = $_SERVER['REMOTE_ADDR'] ?? '';
  345. $model->modules = StringHelper::strUcwords(Yii::$app->controller->module->id);
  346. $model->model_id = intval(str_replace(["_"], "", $this->attributes['id']));
  347. $model->model = $formName;
  348. $model->remark = $remark;
  349. $model->before_content = json_encode($newBeforeUpdate, JSON_UNESCAPED_UNICODE);
  350. $model->after_content = json_encode($newAfterUpdate, JSON_UNESCAPED_UNICODE);
  351. if (!$model->save()) throw new Exception('sql:' . $model->getErrorMessage());
  352. }
  353. }
  354. }
  355. }
  356. } catch (\Exception $e) {
  357. Yii::error('后台操作日志存储失败:第' . $e->getLine() .'行,原因:'. $e->getMessage());
  358. }
  359. parent::afterSave($insert, $changedAttributes); // TODO: Change the autogenerated stub
  360. }
  361. /**
  362. * 获取分页数据
  363. *
  364. * @param integer $limit
  365. * @param callable $callback
  366. * @param string $order_by
  367. * @return array
  368. */
  369. public static function getPaginationList(
  370. int $limit, callable $callback = null, string $order_by = 'id'
  371. ) :array
  372. {
  373. $model = static::find();
  374. if (!empty($callback)) call_user_func($callback, $model);
  375. $pagination = new Pagination(['totalCount' => $model->count(), 'pageSize' => $limit]);
  376. $model->limit($pagination->limit)->offset($pagination->offset);
  377. $list = $model
  378. ->orderBy($order_by)
  379. ->asArray()
  380. ->all();
  381. $data['list'] = $list;
  382. $data['pagination'] = $pagination;
  383. $data['page_count'] = $pagination->pageCount;
  384. $data['row_count'] = $pagination->totalCount;
  385. $data['page_size'] = $pagination->getLimit();
  386. return $data;
  387. }
  388. }