model = new $model(); //主键字段名初始化 $this->pk = $this->model->db()->getPk(); //表名初始化 $this->table_name = $this->model->db()->getTable(); //排序字段名初始化 $this->initSortField(); } /** * 获取排序字段名 */ public function getSortField(): string { return $this->sort_field; } /** * 获取主键字段名 */ public function getPk(): string { return $this->pk; } /** * 排序号新增处理 * * @param array $extra_wheres 关联类型 例:["xxx_type" => 1] * @return int 返回新增所需的最新排序号 */ public function add(array $extra_wheres = []): int { $sort_field = $this->sort_field; $max_sort = $this->model->where($extra_wheres)->order($sort_field, 'desc')->value($sort_field) ?? 0; return ++$max_sort; } /** * 排序号互换处理(数据A <=> 数据B) * * @param string $guid 主键值 * @param int $sort 新排序号 * @param array $extra_wheres 关联类型 例:["xxx_type" => 1] */ public function swap(string $guid, int $sort, array $extra_wheres = []): void { $model = $this->model; $table_name = $this->table_name; $pk = $this->pk; $sort_field = $this->sort_field; //数据A $data_a = $model->where($pk, $guid)->find(); if (!$data_a) { throwErrorMsg('Tool::sortEditProc() : 找不到该数据原排序号', 444); } //数据B //查找当前数据所想更换的新排序号是否已有数据占用(排除自己),这个占用数据则视为数据B $data_b = $model->where($sort_field, $sort)->where($pk, '<>', $guid)->where($extra_wheres)->find(); //数据B存在,开始进行互换处理 if ($data_b) { //【互换内容初始化】 $update_data = []; //检查模型是否有父祖级主键,有则也加入互换 if ($this->isExistFathersAndAncestors()) { $update_data[$model->parent_guid_field] = $data_a[$model->parent_guid_field]; $update_data[$model->ancestors_guid_field] = $data_a[$model->ancestors_guid_field]; } //原字段排序加入互换 $update_data = [$sort_field => $data_a[$sort_field]]; //关联类型也加入互换 foreach ($extra_wheres as $key => $value) { $update_data[$key] = $data_a[$key]; }; //【数据逻辑处理】 //互换数据A与B的关联类型不相同时候,则代表为数据互换跨类型情况 if (self::isAssociationTypeDataSame($data_a, $data_b, $extra_wheres)) { //数据互换不同类型情况-正常互换操作 Db::name($table_name)->where($sort_field, $sort)->where($extra_wheres)->update($update_data); } else { //数据互换跨类型情况-腾位操作 $this->vacate($sort, $extra_wheres); } } } /** * 排序号腾位处理 * * @param int|null $sort 当前排序号 * @param array $wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_type" => 1,...] */ public function vacate($sort, array $wheres = []): void { $sort_field = $this->sort_field; $table_name = $this->table_name; //新增数据的所属排序号已有数据占用,则腾位处理(已占用的数据及其后面所有数据一起排序号腾位+1) if ($this->model->where($sort_field, $sort)->where($wheres)->value($sort_field) !== null) { Db::name($table_name)->where($wheres)->where($sort_field, '>=', $sort)->inc($sort_field)->update(); } } /** * 排序号退位处理 * * @param string $guid 当前主键值 * @param array $correl_fields 关联类型字段 例:["xxx_guid",...] 代表删除排序号时会根据这些字段来关联(例:所属xxx类型、所属xxx系列)来进行排序处理 */ public function back(string $guid, array $correl_fields): void { $model = $this->model; $sort_field = $this->sort_field; //在所删除的数据之后的数据所属排序号将进行减位处理减位-1 $deleted_find = $model->where($this->pk, $guid)->find(); if ($deleted_find) { $con = []; foreach ($correl_fields as $correl_field) { $con[$correl_field] = $deleted_find[$correl_field]; } $model->where($sort_field, '>', $deleted_find[$sort_field])->where($con)->dec($sort_field)->save(); } } /** * 对比数据关联类型是否相同【排序号互换处理】 * * @param object $data_a 互换数据A * @param object $data_b 互换数据B * @param array $extra_wheres 关联类型数组 例:["xxx_type" => 1] */ private static function isAssociationTypeDataSame(object $data_a, object $data_b, array $extra_wheres): bool { foreach ($extra_wheres as $key => $val) { if ($data_a[$key] != $data_b[$key]) { return false; } }; return true; } /** * 检查模型实例父祖级主键字段是否存在【排序号互换处理】 */ private function isExistFathersAndAncestors(): bool { return isset($this->model->parent_guid_field) && isset($this->model->ancestors_guid_field); } /** *初始化排序字段名 */ private function initSortField(): void { if (!isset($this->model->order_field)) { throwErrorMsg('排序处理失败!模型层未定义排序字段$order_field'); } $this->sort_field = $this->model->order_field; } }