Fields.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace app\admin\model\cms;
  3. use addons\cms\library\Alter;
  4. use addons\cms\library\Service;
  5. use app\common\model\Config;
  6. use think\Db;
  7. use think\Exception;
  8. use think\exception\PDOException;
  9. use think\Model;
  10. class Fields extends Model
  11. {
  12. // 表名
  13. protected $name = 'cms_fields';
  14. // 自动写入时间戳字段
  15. protected $autoWriteTimestamp = 'int';
  16. // 定义时间戳字段名
  17. protected $createTime = 'createtime';
  18. protected $updateTime = 'updatetime';
  19. // 追加属性
  20. protected $append = [
  21. 'status_text',
  22. 'content_list',
  23. ];
  24. protected $type = [
  25. 'setting' => 'json',
  26. ];
  27. protected static $listField = ['select', 'selects', 'checkbox', 'radio', 'array', 'selectpage', 'selectpages'];
  28. public function setError($error)
  29. {
  30. $this->error = $error;
  31. }
  32. protected static function init()
  33. {
  34. $beforeUpdateCallback = function ($row) {
  35. $changedData = $row->getChangedData();
  36. if (isset($changedData['name'])) {
  37. if (!preg_match("/^([a-zA-Z0-9_]+)$/i", $row['name'])) {
  38. throw new Exception("字段只支持字母数字下划线");
  39. }
  40. if (is_numeric(substr($row['name'], 0, 1))) {
  41. throw new Exception("字段不能以数字开始");
  42. }
  43. if ($row['source'] == 'model') {
  44. $tableFields = \think\Db::name('cms_archives')->getTableFields();
  45. if (in_array(strtolower($row['name']), $tableFields)) {
  46. throw new Exception("字段已经在主表存在了");
  47. }
  48. if (in_array($row['name'], ['id', 'content'])) {
  49. throw new Exception("字段已经存在");
  50. }
  51. } elseif (in_array($row['source'], ['channel', 'page', 'special', 'block'])) {
  52. //栏目、单页、专题、区块需过滤主表字段
  53. $tableFields = \think\Db::name('cms_' . $row['source'])->getTableFields();
  54. $customFieldList = Service::getCustomFields($row['source'], 0);
  55. $tableFields = array_diff($tableFields, array_map(function ($field) {
  56. return $field['name'];
  57. }, collection($customFieldList)->toArray()));
  58. if (in_array(strtolower($row['name']), $tableFields)) {
  59. throw new Exception("字段已经在表中存在了");
  60. }
  61. } elseif ($row['source'] == 'diyform') {
  62. $tableFields = ['id', 'user_id', 'createtime', 'updatetime', 'memo', 'status'];
  63. if (in_array(strtolower($row['name']), $tableFields)) {
  64. throw new Exception("字段已经存在");
  65. }
  66. } else {
  67. $tableFields = ['id', 'user_id', 'type', 'createtime', 'updatetime'];
  68. if (in_array(strtolower($row['name']), $tableFields)) {
  69. throw new Exception("字段为保留字段,请使用其它字段");
  70. }
  71. }
  72. $vars = array_keys(get_class_vars('\think\Model'));
  73. $vars = array_map('strtolower', $vars);
  74. $vars = array_merge($vars, ['url', 'fullurl']);
  75. if (in_array(strtolower($row['name']), $vars)) {
  76. throw new Exception("字段为模型保留字段,请使用其它字段");
  77. }
  78. }
  79. };
  80. $afterInsertCallback = function ($row) {
  81. //为了避免引起更新的事件回调,这里采用直接执行SQL的写法
  82. Db::name('cms_fields')->update(['id' => $row['id'], 'weigh' => $row['id']]);
  83. Fields::refreshTable($row, 'insert');
  84. };
  85. $afterUpdateCallback = function ($row) {
  86. Fields::refreshTable($row, 'update');
  87. };
  88. self::beforeInsert($beforeUpdateCallback);
  89. self::beforeUpdate($beforeUpdateCallback);
  90. self::afterInsert($afterInsertCallback);
  91. self::afterUpdate($afterUpdateCallback);
  92. self::afterDelete(function ($row) {
  93. Fields::refreshTable($row, 'delete');
  94. });
  95. }
  96. public function getContentListAttr($value, $data)
  97. {
  98. return in_array($data['type'], self::$listField) ? Config::decode($data['content']) : $data['content'];
  99. }
  100. public static function getContributeFields()
  101. {
  102. return ["channel_ids", "image", "images", "tags", "price", "outlink", "content", "keywords", "description"];
  103. }
  104. public static function getPublishFields()
  105. {
  106. return ["channel_ids", "user_id", "special_ids", "image", "images", "diyname", "tags", "price", "outlink", "content", "seotitle", "keywords", "description"];
  107. }
  108. public static function refreshTable($row, $action = 'insert')
  109. {
  110. $model = null;
  111. if (in_array($row['source'], ['model', 'diyform'])) {
  112. $model = $row['source'] == 'model' ? Modelx::get($row['source_id']) : Diyform::get($row['source_id']);
  113. if (!$model) {
  114. throw new Exception("未找到指定模型");
  115. }
  116. $table = $model['table'];
  117. } elseif (in_array($row['source'], ['channel', 'page', 'special', 'block'])) {
  118. $table = "cms_" . $row['source'];
  119. } else {
  120. throw new Exception("未找到指定模型");
  121. }
  122. $alter = Alter::instance();
  123. if (isset($row['oldname']) && $row['oldname'] != $row['name']) {
  124. $alter->setOldname($row['oldname']);
  125. }
  126. $alter
  127. ->setTable($table)
  128. ->setName($row['name'])
  129. ->setLength($row['length'])
  130. ->setContent($row['content'])
  131. ->setDecimals($row['decimals'])
  132. ->setDefaultvalue($row['defaultvalue'])
  133. ->setComment($row['title'])
  134. ->setType($row['type']);
  135. if ($action == 'insert') {
  136. $sql = $alter->getAddSql();
  137. } elseif ($action == 'update') {
  138. $sql = $alter->getModifySql();
  139. } elseif ($action == 'delete') {
  140. $sql = $alter->getDropSql();
  141. } else {
  142. throw new Exception("操作类型错误");
  143. }
  144. //变更模型数据
  145. if ($model) {
  146. $fields = Fields::where('source', $row['source'])->where('source_id', $row['source_id'])->field('name')->column('name');
  147. $model->fields = implode(',', $fields);
  148. $model->save();
  149. }
  150. try {
  151. db()->execute($sql);
  152. } catch (PDOException $e) {
  153. throw new Exception($e->getMessage());
  154. }
  155. }
  156. public function getStatusList()
  157. {
  158. return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
  159. }
  160. public function getStatusTextAttr($value, $data)
  161. {
  162. $value = $value ? $value : $data['status'];
  163. $list = $this->getStatusList();
  164. return isset($list[$value]) ? $list[$value] : '';
  165. }
  166. }