GroupRepository.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\common\repositories\system\groupData;
  12. use app\common\dao\system\groupData\GroupDao;
  13. use app\common\model\system\groupData\SystemGroup;
  14. use app\common\repositories\BaseRepository;
  15. use FormBuilder\Exception\FormBuilderException;
  16. use FormBuilder\Factory\Elm;
  17. use FormBuilder\Form;
  18. use think\db\exception\DataNotFoundException;
  19. use think\db\exception\DbException;
  20. use think\db\exception\ModelNotFoundException;
  21. use think\exception\ValidateException;
  22. use think\facade\Db;
  23. use think\facade\Route;
  24. use think\Model;
  25. /**
  26. * Class GroupRepository
  27. * @package app\common\repositories\system\groupData
  28. * @mixin GroupDao
  29. * @author xaboy
  30. * @day 2020-03-27
  31. */
  32. class GroupRepository extends BaseRepository
  33. {
  34. /**
  35. *
  36. */
  37. const TYPES = ['input' => '文本框', 'number' => '数字框', 'textarea' => '多行文本框', 'radio' => '单选框', 'checkbox' => '多选框', 'select' => '下拉框', 'file' => '文件上传', 'image' => '图片上传', 'images' => '多图上传', 'color' => '颜色选择框', 'label' => '标签', 'cate' => '平台分类'];
  38. /**
  39. * GroupRepository constructor.
  40. * @param GroupDao $dao
  41. */
  42. public function __construct(GroupDao $dao)
  43. {
  44. $this->dao = $dao;
  45. }
  46. /**
  47. * 创建新记录
  48. *
  49. * 本函数用于根据提供的数据创建新的记录。它首先对数据字段进行整理,然后调用DAO层的创建方法来实际执行插入操作。
  50. * 这个方法是业务逻辑层与数据访问层之间的桥梁,它抽象了数据插入的过程,使得上层应用不需要直接与数据库操作语句打交道。
  51. *
  52. * @param array $data 包含待创建记录的数据数组,其中必须包含字段信息。
  53. * @return mixed 返回DAO层创建方法的执行结果,通常是一个自增的ID或者影响行数。
  54. */
  55. public function create(array $data)
  56. {
  57. // 整理字段数据,确保数据格式符合数据库要求
  58. $data['fields'] = $this->tidyFields($data['fields']);
  59. // 调用DAO层的创建方法,实际执行数据插入操作
  60. return $this->dao->create($data);
  61. }
  62. /**
  63. * 更新数据库中特定ID的记录。
  64. *
  65. * 本函数接受一个ID和一组数据,用于更新数据库中相应记录的字段值。
  66. * 首先,它将数据字段进行整理,然后将其转换为JSON格式,这是为了满足数据库字段的特定需求。
  67. * 最后,它调用DAO(数据访问对象)层的update方法,执行实际的数据库更新操作。
  68. *
  69. * @param int $id 要更新的记录的唯一标识符。
  70. * @param array $data 包含要更新的字段及其新值的数组。
  71. * @return bool 返回更新操作的结果,通常是TRUE表示成功,FALSE表示失败。
  72. */
  73. public function update(int $id, array $data)
  74. {
  75. // 整理并序列化数据字段,以满足数据库存储要求
  76. $data['fields'] = json_encode($this->tidyFields($data['fields']));
  77. // 调用DAO方法执行数据库更新操作
  78. return $this->dao->update($id, $data);
  79. }
  80. /**
  81. * 整理字段信息
  82. *
  83. * 该方法用于接收一个字段数组,每个字段数组包含字段的类型、键、名称等信息。
  84. * 方法会验证每个字段的必要属性是否存在,并确保字段的键不重复。
  85. * 最后,它将整理后的字段信息存储在一个新数组中并返回。
  86. *
  87. * @param array $fields 字段数组,包含多个字段的定义
  88. * @return array 整理后的字段信息数组
  89. * @throws ValidateException 如果字段数组为空、字段类型或键缺失、字段键重复,则抛出异常
  90. */
  91. public function tidyFields(array $fields): array
  92. {
  93. // 检查字段数组是否为空,如果为空则抛出异常
  94. if (!count($fields))
  95. throw new ValidateException('字段最少设置一个');
  96. // 初始化用于存储整理后字段信息的数组
  97. $data = [];
  98. // 初始化用于存储已处理字段键的数组
  99. $fieldKey = [];
  100. // 遍历字段数组,对每个字段进行处理
  101. foreach ($fields as $field) {
  102. // 检查字段是否缺少类型定义,如果缺少则抛出异常
  103. if (!isset($field['type']))
  104. throw new ValidateException('字段类型不能为空');
  105. // 检查字段是否缺少键定义,如果缺少则抛出异常
  106. if (!isset($field['field']))
  107. throw new ValidateException('字段key不能为空');
  108. // 检查字段是否缺少名称定义,如果缺少则抛出异常
  109. if (!isset($field['name']))
  110. throw new ValidateException('字段名称不能为空');
  111. // 检查字段键是否重复,如果重复则抛出异常
  112. if (in_array($field['field'], $fieldKey))
  113. throw new ValidateException('字段key不能重复');
  114. // 将字段的键添加到已处理字段键的数组中
  115. $fieldKey[] = $field['field'];
  116. // 整理字段信息,并添加到整理后字段信息的数组中
  117. $data[] = [
  118. 'name' => $field['name'],
  119. 'field' => $field['field'],
  120. 'type' => $field['type'],
  121. 'param' => $field['param'] ?? '', // 如果字段有参数,则使用字段的参数,否则使用空字符串
  122. 'props' => $field['props'] ?? '' // 如果字段有属性,则使用字段的属性,否则使用空字符串
  123. ];
  124. }
  125. // 返回整理后的字段信息数组
  126. return $data;
  127. }
  128. /**
  129. * 创建或编辑组合数据表单
  130. *
  131. * 该方法用于生成一个用于添加或编辑组合数据的表单。表单包含了一系列的输入字段和选择项,
  132. * 用于收集关于组合数据的各种信息,如后台类型、组合数据名称、键等。
  133. *
  134. * @param int|null $id 组合数据的ID,如果为null,则表示创建新组合数据;否则,表示编辑已有的组合数据。
  135. * @param array $formData 表单的初始数据,用于填充表单字段。
  136. * @return Form 返回生成的表单对象。
  137. */
  138. public function form(?int $id = null, array $formData = []): Form
  139. {
  140. // 根据$id的值决定表单提交的URL,如果是新建,则提交到'groupCreate'路由;如果是编辑,则提交到'groupUpdate'路由。
  141. $formUrl = is_null($id) ? Route::buildUrl('groupCreate')->build() : Route::buildUrl('groupUpdate', ['id' => $id])->build();
  142. $form = Elm::createForm($formUrl);
  143. // 定义表单的验证规则和字段。包括选择后台类型、输入组合数据名称、键、说明等字段。
  144. $form->setRule([
  145. // 选择后台类型字段,是一个下拉列表,必须选择。
  146. Elm::select('user_type', '后台类型:', 0)->options([
  147. ['label' => '总后台配置', 'value' => 0],
  148. ['label' => '商户后台配置', 'value' => 1],
  149. ])->placeholder('请选择后台类型')->requiredNum(),
  150. // 输入组合数据名称字段,必须输入。
  151. Elm::input('group_name', '组合数据名称:')->placeholder('请输入组合数据名称')->required(),
  152. // 输入组合数据键字段,必须输入。
  153. Elm::input('group_key', '组合数据key:')->placeholder('请输入组合数据key')->required(),
  154. // 输入组合数据说明字段,非必须。
  155. Elm::input('group_info', '组合数据说明:')->placeholder('请输入组合数据说明'),
  156. // 输入排序字段,是一个数字输入框,默认为0,最大值为99999。
  157. Elm::number('sort', '排序:', 0)->precision(0)->max(99999),
  158. // 字段组,用于定义一组相关的字段,这里包括了类型、名称、键等字段。
  159. Elm::group('fields', '字段:')->rules([
  160. // 选择字段类型,是一个必选的下拉列表,选项根据self::TYPES动态生成。
  161. Elm::select('type', '类型:')->required()->options(function () {
  162. $options = [];
  163. foreach (self::TYPES as $value => $label) {
  164. $options[] = compact('value', 'label');
  165. }
  166. return $options;
  167. }),
  168. // 输入字段名称字段。
  169. Elm::input('name', '字段名称:')->placeholder('请输入字段名称'),
  170. // 输入字段键字段。
  171. Elm::input('field', '字段key:')->placeholder('请输入字段key'),
  172. // 输入选择项字段,用于配置多选框等需要选择项的字段类型。
  173. Elm::textarea('param', '选择项:'),
  174. // 输入配置字段,用于配置字段的额外属性。
  175. Elm::textarea('props', '配置:'),
  176. ]),
  177. ]);
  178. // 设置表单的标题,并根据$id的值决定是添加还是编辑组合数据。最后设置表单的初始数据。
  179. return $form->setTitle(is_null($id) ? '添加组合数据' : '编辑组合数据')->formData($formData);
  180. }
  181. /**
  182. * 更新表单数据。
  183. * 该方法通过指定的ID获取表单数据,并使用这些数据来更新表单。
  184. * 主要用于在前端展示已存在数据的表单,以便用户可以查看并修改这些数据。
  185. *
  186. * @param int $id 表单数据的唯一标识ID。
  187. * @return array|Form
  188. */
  189. public function updateForm(int $id)
  190. {
  191. // 通过ID获取表单数据,并转换为数组格式,用于更新表单
  192. return $this->form($id, $this->dao->get($id)->toArray());
  193. }
  194. /**
  195. * 分页获取数据列表
  196. *
  197. * 本函数用于根据指定的页码和每页数据量来获取数据列表,并同时返回数据总数。
  198. * 这样可以在前端实现分页功能,展示数据时既可以知道总数据量,也可以根据页码获取对应页的数据。
  199. *
  200. * @param int $page 当前页码,用于指定要获取哪一页的数据。
  201. * @param int $limit 每页的数据量,用于指定每页显示多少条数据。
  202. * @return array 返回包含数据列表和数据总数的数组。
  203. */
  204. public function page(int $page, int $limit)
  205. {
  206. // 根据页码和每页数据量进行分页查询,并隐藏某些字段,按创建时间降序排序
  207. $list = $this->dao->page($page, $limit)->hidden(['fields', 'sort'])->order('create_time DESC')->select();
  208. // 统计总数据量
  209. $count = $this->dao->count();
  210. // 将数据总数和数据列表一起返回
  211. return compact('count', 'list');
  212. }
  213. /**
  214. * 获取指定ID对应字段的键名列表
  215. *
  216. * 本函数通过查询特定ID的字段信息,然后提取出这些信息中的键名,最终返回一个包含所有键名的数组。
  217. * 这样做的目的是为了提供一种方式,以字段键名为基础,进行后续的数据处理或检索操作。
  218. *
  219. * @param int $id 需要查询的记录ID
  220. * @return array 返回包含所有字段键名的数组
  221. */
  222. public function keys(int $id): array
  223. {
  224. // 使用array_column函数从字段信息数组中提取出所有字段的键名
  225. return array_column($this->fields($id), 'field');
  226. }
  227. /**
  228. * 删除记录并清理关联数据。
  229. *
  230. * 本函数通过开启数据库事务,确保删除操作和关联数据清理操作要么同时成功,
  231. * 要么同时失败,以维护数据的一致性。具体操作包括:
  232. * 1. 删除指定ID的记录。
  233. * 2. 清理与被删除记录相关的分组数据。
  234. *
  235. * @param int $id 需要删除的记录的ID。
  236. */
  237. public function delete($id)
  238. {
  239. // 开启数据库事务处理
  240. Db::transaction(function () use ($id) {
  241. // 删除指定ID的记录
  242. $this->delete($id);
  243. // 实例化分组数据仓库,用于后续的清理操作
  244. /** @var GroupDataRepository $make */
  245. $make = app()->make(GroupDataRepository::class);
  246. // 清理与被删除记录相关的分组数据
  247. $make->clearGroup($id);
  248. });
  249. }
  250. /***
  251. * 处理关联字段显示
  252. * @param $fields
  253. * @return array
  254. *
  255. * @date 2023/09/09
  256. * @author yyw
  257. */
  258. public function handleFields($fields = [])
  259. {
  260. foreach ($fields as &$field) {
  261. switch ($field['type']) {
  262. case 'label':
  263. case 'cate':
  264. $field['field'] = $field['type'] . '_name';
  265. break;
  266. }
  267. }
  268. return $fields;
  269. }
  270. }