├── .gitignore
├── resources
├── assets
│ └── images
│ │ └── timg.jpg
└── views
│ ├── tabs.blade.php
│ ├── script.blade.php
│ ├── field
│ └── testtext.blade.php
│ ├── tree.blade.php
│ └── tips.blade.php
├── .github
└── ISSUE_TEMPLATE
│ └── custom.md
├── routes
└── web.php
├── src
├── Field
│ ├── Outer.php
│ └── TestText.php
├── FormWgt.php
├── Configx.php
├── ConfigxServiceProvider.php
├── ConfigxModel.php
├── Http
│ └── Controllers
│ │ └── ConfigxController.php
└── Tools
│ ├── Displayer.php
│ ├── Tree.php
│ ├── Tool.php
│ ├── Updater.php
│ └── Builder.php
├── composer.json
├── LICENSE
├── ChangeLog.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | phpunit.phar
3 | /vendor
4 | composer.phar
5 | composer.lock
6 | *.project
7 | .idea/
--------------------------------------------------------------------------------
/resources/assets/images/timg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ichynul/configx/HEAD/resources/assets/images/timg.jpg
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | html = $html;
18 | }
19 |
20 | public function render()
21 | {
22 | return $this->html;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Field/TestText.php:
--------------------------------------------------------------------------------
1 | 2,
16 | 'field' => 4,
17 | ];
18 |
19 | /**
20 | * Determine if form fields has files.
21 | *
22 | * @return bool
23 | */
24 | public function hasFile()
25 | {
26 | return true;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Configx.php:
--------------------------------------------------------------------------------
1 | views()) {
22 | $this->loadViewsFrom($views, 'configx');
23 | }
24 |
25 | $this->app->booted(function () {
26 | Configx::routes(__DIR__ . '/../routes/web.php');
27 | });
28 |
29 | Admin::booting(function () {
30 |
31 | Form::extend('test_text', TestText::class);
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/resources/views/tabs.blade.php:
--------------------------------------------------------------------------------
1 | Example:
2 |
3 | base : Base setting
4 | shop : Shop setting
5 | uplaod : Upload setting
6 | image :
7 |
8 | This will override `extensions.iframe-tabs.tabs` in config /config/admin.php:
9 |
10 | 'extensions' => [
11 | 'configx' => [
12 | // Set to `false` if you want to disable this extension
13 | 'enable' => true,
14 | 'tabs' => [
15 | 'base' => 'Base',
16 | 'shop' => 'Shop',
17 | 'uplaod' => 'Uplaod',
18 | 'image' => '' // if tab name is empty, get from trans : trans('admin.configx.tabs.image');
19 | ],
20 | // Whether check group permissions.
21 | //if (!Admin::user()->can('confix.tab.base')) {/*hide base tab*/ } .
22 | 'check_permission' => false
23 | ],
24 | ],
25 |
--------------------------------------------------------------------------------
/resources/views/script.blade.php:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ichynul/configx",
3 | "description": "laravel-admin extension configx",
4 | "type": "library",
5 | "keywords": ["laravel-admin", "extension"],
6 | "homepage": "https://github.com/ichynul/configx",
7 | "license": "MIT",
8 | "authors": [{
9 | "name": "ichynul",
10 | "email": "ichynul@outlook.com"
11 | }],
12 | "require": {
13 | "php": ">=7.0.0",
14 | "encore/laravel-admin": "~1.6",
15 | "laravel-admin-ext/config": "^1.0",
16 | "ichynul/row-table": "^1.1.0"
17 | },
18 | "require-dev": {
19 | "phpunit/phpunit": "~6.0"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "Ichynul\\Configx\\": "src/"
24 | }
25 | },
26 | "extra": {
27 | "laravel": {
28 | "providers": [
29 | "Ichynul\\Configx\\ConfigxServiceProvider"
30 | ]
31 |
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jens Segers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/src/ConfigxModel.php:
--------------------------------------------------------------------------------
1 | get()->toArray();
21 | }
22 |
23 | /**
24 | * Get name prefix
25 | *
26 | * @return string
27 | */
28 | public function getPrefix()
29 | {
30 | $arr = explode('.', $this->name);
31 | return count($arr) ? $arr[0] : '';
32 | }
33 |
34 | /**
35 | * Create prefix permission
36 | *
37 | * @param [string] $prefix
38 | * @return void
39 | */
40 | public static function createPermission($prefix, $name)
41 | {
42 | $slug = 'confix.tab.' . $prefix;
43 | $name = trans('admin.configx.header') . '-' . $name;
44 | if ($pm = Permission::where('slug', $slug)->first()) {
45 | if ($pm->name != $name) {
46 | $pm->update(['name' => $name]);
47 | }
48 | return;
49 | }
50 | Permission::create([
51 | 'name' => $name,
52 | 'slug' => $slug,
53 | 'http_path' => "/configx/tab-{$prefix}",
54 | ]);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/resources/views/field/testtext.blade.php:
--------------------------------------------------------------------------------
1 |
68 |
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | ## 2019 年 4 月 10 日
2 |
3 | #1.0.18
4 |
5 | - 1. If tab name is empty , get from trans : `trans("admin.configx.tabs.{$tabkey}")`;
6 |
7 | tab 名称留空则从翻译中获取
8 |
9 | ```php
10 | 'extensions' => [
11 | 'configx' => [
12 | // *****
13 | 'tabs' => [
14 | 'base' => '基本设置',
15 | 'shop' => '店铺设置',
16 | 'uplaod' => '上传设置',
17 | 'image' => '' // if tab name is empty , get from trans : trans('admin.configx.tabs.image'); 留空则从翻译中获取名称
18 | ],
19 | // *****
20 | ],
21 | ],
22 |
23 | ```
24 |
25 | - 2. When adding or editing a config , you can type in a `config_name` optionaly,
26 |
27 | if `new_config_name` is empty, get from trans : `trans("admin.configx.{$tab}.{$config_key}")`;
28 |
29 | 添加或编辑配置信息时,可以输入配置名称,如若留空,则从翻译中获取
30 |
31 | ## 2019 年 3 月 22 日
32 |
33 | New feature support varable key some\_$admin$\_str.
34 | 新特性,支持在 key 中插入可变的$admin$
35 |
36 | # demo
37 |
38 | Add 2 config keys :
39 |
40 | ```
41 | base.skin_$admin$
42 | element type : radio_group
43 | options :
44 | skin-blue
45 | skin-blue-light
46 | skin-yellow
47 | skin-yellow-light
48 | skin-green
49 | skin-green-light
50 | skin-purple
51 | skin-purple-light
52 | skin-red
53 | skin-red-light
54 | skin-black
55 | skin-black-light
56 |
57 | base.layout_$admin$
58 | element type : checkbox_group
59 | options :
60 | fixed
61 | layout-boxed
62 | layout-top-nav
63 | sidebar-collapse
64 | sidebar-mini
65 | ```
66 |
67 | Then add some codes at `Admin/bootstrap.php` :
68 |
69 | ```php
70 | if(Admin::user())
71 | {
72 | config(
73 | [
74 | 'admin.skin' => config('base.skin_admin_' . Admin::user()->id, 'skin-blue'),
75 | 'admin.layout' => explode(',', config('base.layout_admin_' . Admin::user()->id, 'fixed')),
76 | ]
77 | );
78 | }
79 | ```
80 |
--------------------------------------------------------------------------------
/src/Http/Controllers/ConfigxController.php:
--------------------------------------------------------------------------------
1 | input('do');
19 |
20 | $__configx__ = Tool::getConfigx();
21 |
22 | $cx_options = [];
23 |
24 | if ($__configx__ && $__configx__['description']) {
25 |
26 | $cx_options = json_decode($__configx__['description'], 1);
27 | }
28 |
29 | $tabs = Tool::tabs($cx_options);
30 |
31 | if ($do == 'backup') {
32 |
33 | $this->backUp($__configx__);
34 |
35 | $do = 'new_config';
36 | }
37 |
38 | if ($do == 'new_config') {
39 |
40 | return Displayer::newConfig($id, $cx_options, $tabs);
41 |
42 | } else if ($do == 'tabs_config') {
43 |
44 | return Displayer::tabsConfig($id, $cx_options, $tabs);
45 | }
46 |
47 | return Displayer::editConfigs($id, $cx_options, $tabs);
48 | }
49 |
50 | public function saveall($id = 0, Request $request)
51 | {
52 | $do = $request->input('do');
53 |
54 | if ($do == 'tabs_config') {
55 |
56 | return Updater::saveTabsOptions($id, $request->values['c_tabs_options']);
57 | }
58 |
59 | if ($do == 'new_config' || $do == 'backup') {
60 |
61 | return Updater::saveConfigOptions($id, $request);
62 | }
63 |
64 | return Updater::saveConfigs($id, $request);
65 | }
66 |
67 | public function postSort(Request $request)
68 | {
69 | $__configx__ = Tool::getConfigx();
70 |
71 | $cx_options = [];
72 |
73 | if ($__configx__ && $__configx__['description']) {
74 |
75 | $cx_options = json_decode($__configx__['description'], 1);
76 | }
77 |
78 | $data = $request->input('data');
79 |
80 | $i = 0;
81 | foreach ($data as $s) {
82 | $i += 5;
83 | $id = $s['id'];
84 | $config = ConfigxModel::findOrFail($id);
85 | if (isset($cx_options[$config['name']])) {
86 | $cx_options[$config['name']]['order'] = $i;
87 | } else {
88 | $cx_options[$config['name']] = ['options' => [], 'element' => 'normal', 'help' => '', 'name' => '', 'order' => $i];
89 | }
90 | }
91 | $cx_options = Tool::remove($cx_options);
92 | $__configx__['description'] = json_encode($cx_options);
93 | $__configx__->save();
94 | return response()->json(['status' => 1, 'message' => trans('admin.update_succeeded')]);
95 | }
96 |
97 | public function delFile($id, Request $request)
98 | {
99 | $rowname = 'c_' . $id . '_';
100 |
101 | $field = new MultipleFile($rowname, ['']);
102 |
103 | $config = ConfigxModel::findOrFail($id);
104 |
105 | $field->setOriginal([$rowname => explode(',', $config->value)]);
106 |
107 | $this->handleFileDelete($request->all());
108 |
109 | $value = $field->destroy($request->input(Field::FILE_DELETE_FLAG));
110 |
111 | $value = implode(',', $value);
112 |
113 | $config->value = $value;
114 | $config->update();
115 |
116 | return response()->json(['status' => 1, 'message' => trans('admin.update_succeeded')]);
117 | }
118 |
119 | protected function handleFileDelete($input)
120 | {
121 | if (array_key_exists(Field::FILE_DELETE_FLAG, $input)) {
122 | $input[Field::FILE_DELETE_FLAG] = $input['key'];
123 | unset($input['key']);
124 | }
125 |
126 | request()->replace($input);
127 | }
128 |
129 | protected function backUp($__configx__)
130 | {
131 | if ($__configx__ && $__configx__['description']) {
132 | app('files')->put(
133 | storage_path('app/public/configx.json'),
134 | $__configx__['description']
135 | );
136 |
137 | admin_success(trans('admin.succeeded'), "Configx options save to : /wwwroot/storage/app/public/configx.json");
138 | } else {
139 | admin_warning(trans('admin.failed'), "Configx options is empty!");
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/resources/views/tree.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | @foreach($tree as $title => $fields)
7 |
8 | {!! $title !!}
9 | @if($tabsEdit)
10 |
11 |
12 |
13 | @endif
14 |
15 |
16 |
17 |
18 | @foreach($fields as $field)
19 | @if(isset($field['options']) && \Illuminate\Support\Arr::get($field['options'],'divide') =='befor')
20 | - - - - - - - - - - - - - -
21 | @endif
22 |
23 | {!! $field['label'] !!}-[{!! $field['type_name'] !!}]
24 |
25 |
26 | @if($field['id'] != $current_id)
27 |
28 | @else
29 |
30 | @endif
31 |
32 | @if(isset($field['tds']) && count($field['tds']))
33 |
34 | @foreach($field['tds'] as $td)
35 | {!! $td['label'] !!} -[{!! $td['type_name'] !!}]
36 |
37 |
38 | @endforeach
39 |
40 | @endif
41 |
42 | @if(isset($field['options']) && \Illuminate\Support\Arr::get($field['options'],'divide') =='after')
43 | - - - - - - - - - - - - - -
44 | @endif
45 | @endforeach
46 |
47 |
48 | @endforeach
49 |
50 |
51 |
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # laravel-admin configx
2 |
3 | ## Installation
4 |
5 | need to install laravel-admin-ext/config first, see https://github.com/laravel-admin-extensions/config
6 |
7 | Then run :
8 |
9 | ```
10 | $ composer require ichynul/configx
11 | ```
12 |
13 | Then run:
14 |
15 | ```
16 | $ php artisan admin:import configx
17 | ```
18 |
19 | Add a tabs config in `config/admin.php`:
20 |
21 | ```php
22 | 'extensions' => [
23 | 'configx' => [
24 | // Set to `false` if you want to disable this extension
25 | 'enable' => true,
26 | 'tabs' => [
27 | 'base' => '基本设置',
28 | 'shop' => '店铺设置',
29 | 'uplaod' => '上传设置',
30 | 'image' => '' // if tab name is empty, get from trans : trans('admin.configx.tabs.image'); tab名称留空则从翻译中获取
31 | ],
32 | // Whether check group permissions.
33 | //if (!Admin::user()->can('confix.tab.base')) {/*hide base tab*/ } .
34 | 'check_permission' => false,
35 | 'break_when_errors' => false // do not save anything if have errors
36 | ],
37 | ],
38 |
39 | ```
40 |
41 | ## Usage
42 |
43 | Open `http://your-host/admin/configx/edit`
44 |
45 | ## Demo
46 |
47 | You can click "+" to config tabs :
48 |
49 | add an new config key
50 |
51 | step 1 Select config type from `['base']`
52 |
53 | step 2 Select form-element type from `['normal', 'date', 'time', 'datetime', 'image', 'yes_or_no', 'number', 'rate', 'editor', 'radio_group' ,'checkbox_group', 'select']`... and so on
54 |
55 | step 3 If you selected form-element type is `['radio_group' ,'checkbox_group', 'select']` ,you need inupt `[options]` :
56 |
57 | just text:
58 |
59 | ```js
60 | text1
61 | text2
62 | ...
63 | ```
64 |
65 | and key-text:
66 |
67 | ```js
68 | key1 : text1
69 | key2 : text2
70 | ...
71 | ```
72 |
73 | or load from ulr:
74 |
75 | `options_url:/api/mydata`
76 |
77 | If you selected form-element type is `textarea` , you can config it `rows:3` , default is 5.
78 |
79 | If you selected form-element type is `table`, `rows / cols` is needed :
80 |
81 | `base.some_key`
82 |
83 | ```
84 | rows: 4
85 | cols: 4
86 | ```
87 |
88 | This wiil build a table like below :
89 |
90 | ````php
91 | /*
92 | |-------------------------------------------------------------------------------------
93 | | r_label\ c_labe | c_label1 | c_label2 | c_label3 | ⬅Col labels
94 | |-------------------------------------------------------------------------------------
95 | | r_label1 | base.some_key_1_1 | base.some_key_1_2 | base.some_key_1_3 |
96 | |-------------------------------------------------------------------------------------
97 | | r_label2 | base.some_key_2_1 | base.some_key_2_2 | base.some_key_2_3 |
98 | |-------------------------------------------------------------------------------------
99 | | r_label3 | base.some_key_3_1 | base.some_key_3_2 | base.some_key_3_3 |
100 | |-------------------------------------------------------------------------------------
101 | ↑
102 | Row labels
103 |
104 | You can edit labels as you want.
105 |
106 | Each has a key , base.some_key_[0]_[0] to base.some_key_[rows-1]_[cols-1] . (from 0 to length -1 )
107 |
108 | So, you can chang a label to input :
109 |
110 | |-------------------------------------------------------------------------------------
111 | | r_label\ c_labe | c_label1 | c_label2 | base.some_key_0_3 | ⬅ [c_label3] change to [base.some_key_0_3]
112 | |------------------------------------------------------------------------------------- , we can input here .
113 | | r_label1 | base.some_key_1_1 | base.some_key_1_2 | base.some_key_1_3 | (可以把label 换成输入元素)
114 | |-------------------------------------------------------------------------------------
115 | | r_label2 | base.some_key_2_1 | base.some_key_2_2 | base.some_key_2_3 |
116 | |-------------------------------------------------------------------------------------
117 | | trans.sometext | base.some_key_3_1 | hello world! | base.some_key_3_3 |
118 | |-------------------------------------------------------------------------------------
119 | ↑ ↑
120 | ↑ [base.some_key_3_2] change to [hello world!]
121 | ↑ , we can not input here any more ,
122 | ↑ it wiil just show label text 'hello world!' .
123 | ↑ (也可以把输入元素换成仅显示文字)
124 | ↑
125 | get text from trans
126 | trans("admin.configx.base.some_key.sometext")
127 | 显示文字时可以从翻译获取文字,样式 `trans.sometext`
128 | 其中 sometext 为翻译的key
129 |
130 |
131 |
132 | note : if text = key or text = '' ,render as input form element , otherwise just show the text you leave.
133 |
134 | //if text is trans.sometext , get from trans : trans("admin.configx.{$tab}.{$tablekey}.{$sometext}")
135 |
136 | 总结 : 如果输入的字符串与td默认key一样或输入的字符串为空,这个位置将是一个可输入的表单元素,否则就显示原样你输入的字符串 .
137 |
138 |
139 | */
140 | Add a lang config in `resources/lang/{zh-CN}/admin.php`
141 |
142 | ```php
143 | 'configx' => [
144 | 'new_config_type' => '配置类型',
145 | 'new_config_key' => '配置key',
146 | 'new_config_name' => '配置名称',
147 | 'new_config_element' => '配置表单元素',
148 | 'new_config_help' => '配置help',
149 | 'new_config_options' => '配置扩展项',
150 | 'header' => '网站设置',
151 | 'desc' => '网站设置设置',
152 | 'backup' => '备份',
153 | 'element' => [
154 | 'normal' => '默认',
155 | 'textarea' => '文本域',
156 | 'date' => '日期',
157 | 'time' => '时间',
158 | 'datetime' => '日期时间',
159 | 'password' => '密码',
160 | 'image' => '图片',
161 | 'multiple_image' => '多图',
162 | 'file' => '文件',
163 | 'multiple_file' => '多文件',
164 | 'yes_or_no' => '是或否',
165 | 'editor' => '编辑器',
166 | 'radio_group' => '单选框组',
167 | 'checkbox_group' => '多选框组',
168 | 'number' => '数字',
169 | 'rate' => '比例',
170 | 'select' => '下拉框',
171 | 'tags' => '标签',
172 | 'icon' => '图标',
173 | 'color' => '颜色',
174 | 'table' =>'表格',
175 | 'listbox' => '左右多选框',
176 | 'multiple_select' => '下拉多选',
177 | 'map' => '地图'
178 | ],
179 | ],
180 | 'yes' => '是',
181 | 'no' => '否'
182 | ````
183 |
184 | if you need add a new config tab, chang it in `config/admin.php`.
185 |
186 | After add config in the panel, use `config($key)` to get value you configured.
187 |
188 | License
189 |
190 | ---
191 |
192 | Licensed under [The MIT License (MIT)](LICENSE).
193 |
--------------------------------------------------------------------------------
/src/Tools/Displayer.php:
--------------------------------------------------------------------------------
1 | request('do', ''), 'tabindex' => Session::get('tabindex')]);
34 | }
35 |
36 | return static::$formWgt;
37 | }
38 |
39 | public static function newConfig($id = 0, $cx_options = [], $tabs)
40 | {
41 | if (Tool::checkPermission()) {
42 |
43 | if (!Admin::user()->can('confix.tab.' . 'new_config')) {
44 | return '';
45 | }
46 | }
47 |
48 | Tree::getConfigTabs($tabs, $cx_options);
49 |
50 | $config = [];
51 | $tab = new Wtab();
52 |
53 | if ($id > 0) {
54 | $config = ConfigxModel::findOrFail($id);
55 | $label = $cx_options && isset($cx_options[$config['name']]) ? Arr::get($cx_options[$config['name']], 'name') : '';
56 | if (!$label) {
57 | $label = trans('admin.configx.' . $config['name']);
58 | }
59 | $title = trans('admin.edit') . '-' . $label;
60 | } else {
61 | $title = trans('admin.create');
62 | }
63 |
64 | $subs = array(
65 | ['id' => 'type', 'name' => 'new_config_type', 'value' => ''],
66 | ['id' => 'key', 'name' => 'new_config_key', 'value' => ''],
67 | ['id' => 'name', 'name' => 'new_config_name', 'value' => ''],
68 | ['id' => 'element', 'name' => 'new_config_element', 'value' => ''],
69 | ['id' => 'help', 'name' => 'new_config_help', 'value' => ''],
70 | ['id' => 'options', 'name' => 'new_config_options', 'value' => ''],
71 | );
72 |
73 | $formhtml = '';
74 |
75 | foreach ($subs as $val) {
76 | $formhtml .= Builder::createNewConfigForm($val, $tabs, $cx_options, $config);
77 | }
78 |
79 | if ($id > 0) {
80 | $tab->add($title, '' . $formhtml . '
' . Tree::buildTree($id, $cx_options) . '
', false);
81 | } else {
82 | $tab->add($title, '' . $formhtml . '
' . Tree::buildTree($id, $cx_options) . '
', false);
83 | }
84 | $tab->addLink('x', admin_base_path('configx/edit/0'));
85 |
86 | return static::createform($tab, $id);
87 | }
88 |
89 | public static function tabsConfig($id = 0, $cx_options = [], $tabs)
90 | {
91 | if (Tool::checkPermission()) {
92 |
93 | if (!Admin::user()->can('confix.tab.' . 'tabs_config')) {
94 | return '';
95 | }
96 | }
97 |
98 | $tab = new Wtab();
99 |
100 | $title = trans('admin.edit') . '-' . trans('admin.configx.' . 'new_config_type');
101 |
102 | $subs = array(
103 | ['id' => 'tabs_key', 'name' => 'new_config_key', 'value' => ''],
104 | ['id' => 'tabs_options', 'name' => 'new_config_options', 'value' => ''],
105 | );
106 |
107 | $formhtml = '';
108 |
109 | foreach ($subs as $val) {
110 | $formhtml .= Builder::createNewConfigForm($val, $tabs, $cx_options);
111 | }
112 |
113 | $tab->add($title, '', true);
114 | $tab->addLink('x', admin_base_path('configx/edit/' . $id) . '?do=new_config');
115 |
116 | return static::createform($tab, $id);
117 | }
118 |
119 | public static function editConfigs($id = 0, $cx_options = [], $tabs)
120 | {
121 | $tab = new Wtab();
122 |
123 | if (Tool::checkPermission()) {
124 |
125 | Tool::createPermissions($tabs);
126 |
127 | Tool::createPermissions(['new_config' => trans('admin.edit') . '-config']);
128 |
129 | Tool::createPermissions(['tabs_config' => trans('admin.edit') . '-tabs']);
130 | }
131 |
132 | Tree::getConfigTabs($tabs, $cx_options);
133 |
134 | $tree = Tree::getTree();
135 |
136 | foreach ($tree as $title => $fields) {
137 | $formhtml = '';
138 | foreach ($fields as $field) {
139 | $formhtml .= Builder::createField($field, $cx_options);
140 | }
141 | $tab->add($title, '' . $formhtml . '
', false);
142 | }
143 |
144 | if (!Tool::checkPermission() || Admin::user()->can('confix.tab.' . 'new_config')) {
145 |
146 | $tab->addLink('+', admin_base_path('configx/edit/0') . '?do=new_config');
147 | }
148 |
149 | return static::createform($tab, $id);
150 | }
151 |
152 | protected static function createform($tab, $id)
153 | {
154 | $indexField = new Hidden('tabindex', 'tabindex');
155 | $indexField->default(0);
156 |
157 | $doField = new Hidden('do', 'do');
158 |
159 | $form = static::getFormWgt();
160 |
161 | $html = new Outer($tab->render(), []);
162 |
163 | $form->pushField($html);
164 | $form->pushField($indexField);
165 | $form->pushField($doField);
166 | $form->action(admin_base_path('configx/saveall/' . $id));
167 | $form->attribute('enctype', 'multipart/form-data');
168 |
169 | $content = new Content();
170 |
171 | return $content
172 | ->header(trans('admin.configx.header'))
173 | ->description(trans('admin.configx.desc'))
174 | ->breadcrumb(
175 | ['text' => trans('admin.configx.header'), 'url' => 'configx/edit'],
176 | ['text' => trans('admin.configx.desc')]
177 | )
178 | ->row('' . $form->render() . '
')->row(view(
179 | 'configx::script',
180 | [
181 | 'call_back' => admin_base_path('configx/sort'),
182 | 'del_url' => admin_base_path('config'),
183 | 'deleteConfirm' => trans('admin.delete_confirm'),
184 | 'confirm' => trans('admin.confirm'),
185 | 'cancel' => trans('admin.cancel'),
186 | ]
187 | ));
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/Tools/Tree.php:
--------------------------------------------------------------------------------
1 | &$value) {
30 | if ($check_permission && !Admin::user()->can('confix.tab.' . $key)) {
31 | continue;
32 | }
33 | $subs = ConfigxModel::group($key);
34 | if ($cx_options) {
35 | $subs = Tool::sortGroupConfigs($subs, $cx_options);
36 | }
37 |
38 | static::$tree[$value] = [];
39 |
40 | if (empty($subs)) {
41 | continue;
42 | }
43 | foreach ($subs as $val) {
44 | if (!isset($cx_options[$val['name']])) {
45 | $cx_options[$val['name']] = [
46 | 'options' => [],
47 | 'element' => 'normal',
48 | 'help' => '',
49 | 'name' => '',
50 | 'order' => 999,
51 | ];
52 | }
53 | if (preg_match('/\$admin\$/i', $val['name'])) {
54 | $old = $val['name'];
55 | $new = preg_replace('/\$admin\$/i', 'admin_' . Admin::user()->id, $old);
56 | $val = ConfigxModel::firstOrCreate(
57 | ['name' => $new],
58 | [
59 | 'description' => trans('admin.configx.' . $val['name']) . ' for admin-' . Admin::user()->id,
60 | 'value' => '1',
61 | ]
62 | );
63 | $val['name'] = $old;
64 | }
65 | if (preg_match('/admin_\d+?/i', $val['name'])) {
66 | continue;
67 | }
68 | $val['etype'] = Arr::get($cx_options[$val['name']], 'element', 'normal');
69 |
70 | if (isset($cx_options[$val['name']]['table_field'])) {
71 |
72 | static::$tableFields[$val['name']] = $val;
73 | continue;
74 | }
75 | static::$tree[$value][] = $val;
76 | }
77 | }
78 | }
79 |
80 | public static function buildTree($id = 0, $cx_options = [])
81 | {
82 | $tree = static::$tree;
83 | $tableFields = static::$tableFields;
84 |
85 | $editTitle = trans('admin.edit');
86 | $deleteTitle = trans('admin.delete');
87 | $saveTitle = trans('admin.configx.backup');
88 | $tabsEdit = !Tool::checkPermission() || Admin::user()->can('confix.tab.' . 'tabs_config') ?
89 | admin_base_path('configx/edit/' . $id) . '?do=tabs_config' : '';
90 |
91 | foreach ($tree as &$fields) {
92 | foreach ($fields as &$field) {
93 |
94 | if (!key_exists($field['name'], $cx_options)) {
95 | $cx_options[$field['name']] = [];
96 | }
97 |
98 | $options = Arr::get($cx_options[$field['name']], 'options', []);
99 |
100 | $label = Arr::get($cx_options[$field['name']], 'name');
101 | if (!$label) {
102 | $label = trans('admin.configx.' . $field['name']);
103 | }
104 | $field['label'] = $label;
105 | $field['options'] = $options;
106 | $field['href'] = admin_base_path('configx/edit/' . $field['id']) . '?do=new_config';
107 | $field['type_name'] = trans('admin.configx.element.' . $field['etype']);
108 | if ($field['etype'] == 'normal' && isset($options['__element__'])) {
109 | $field['type_name'] .= '+';
110 | }
111 |
112 | if (preg_match('/\$admin\$/i', $field['name'])) {
113 | $etype = $field['etype'];
114 | $field = ConfigxModel::firstOrCreate(
115 | ['name' => $field['name']],
116 | [
117 | 'description' => trans('admin.configx.' . $field['name']),
118 | 'value' => 'do not delete',
119 | ]
120 | );
121 | $field['etype'] = $etype;
122 | }
123 | if ($field['etype'] == 'table') {
124 | $tableInfo = json_decode($field['description'], 1);
125 | if ($tableInfo) {
126 | $tds = [];
127 | foreach ($tableInfo as $tk => $tv) {
128 | if (!isset($tableFields[$tk])) {
129 | continue;
130 | }
131 | $tds[$tk] = $tableFields[$tk];
132 | $toptions = [];
133 | if (isset($cx_options[$tk])) {
134 | $toptions = Arr::get($cx_options[$tk], 'options', []);
135 | }
136 | $label = Arr::get($cx_options[$tk], 'name');
137 | if (!$label) {
138 | $label = trans('admin.configx.' . $tk);
139 | }
140 | $tds[$tk]['label'] = $label;
141 | $tds[$tk]['href'] = admin_base_path('configx/edit/' . $tableFields[$tk]['id']) . '?do=new_config';
142 | $tds[$tk]['options'] = $toptions;
143 | $tds[$tk]['type_name'] = trans('admin.configx.element.' . $tableFields[$tk]['etype']);
144 | if ($tableFields[$tk]['etype'] == 'normal' && isset($toptions['__element__'])) {
145 | $tds[$tk]['type_name'] .= '+';
146 | }
147 | }
148 | $field['tds'] = $tds;
149 | }
150 | }
151 | }
152 | }
153 |
154 | return view('configx::tree', [
155 | 'current_id' => $id,
156 | 'tree' => $tree,
157 | 'editTitle' => $editTitle,
158 | 'deleteTitle' => $deleteTitle,
159 | 'saveTitle' => $saveTitle,
160 | 'tabsEdit' => $tabsEdit,
161 | 'call_back' => admin_base_path('configx/sort'),
162 | 'del_url' => admin_base_path('config'),
163 | 'deleteConfirm' => trans('admin.delete_confirm'),
164 | 'confirm' => trans('admin.confirm'),
165 | 'cancel' => trans('admin.cancel'),
166 | ]);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/Tools/Tool.php:
--------------------------------------------------------------------------------
1 | $v) {
19 | if (preg_match('/^@\w+/', $k)) {
20 | continue;
21 | }
22 | if ($k == 'divide' && in_array($v, ['befor', 'after'])) {
23 | continue;
24 | }
25 |
26 | $_options[$k] = $v;
27 | }
28 |
29 | return $_options;
30 | }
31 |
32 | public static function callUserfunctions($field, $options)
33 | {
34 | foreach ($options as $k => $v) {
35 | if (preg_match('/^@\w+/', $k)) {
36 | $args = array_filter(explode(',', $v));
37 | $args = collect($args)->map(function ($s) {
38 | $s = trim($s);
39 | if (preg_match('/^\d+$/', $s)) {
40 | return intval($s);
41 | }
42 | if (preg_match('/^\d+\.\d+$/', $s)) {
43 | return doubleval($s);
44 | }
45 | if (preg_match('/^(false|true)$/i', $s)) {
46 | return strtolower($s) == 'true';
47 | }
48 | return preg_replace("/^\s*['\"]|['\"]\s*$/", '', $s);
49 | })->all();
50 |
51 | $method = str_replace('@', '', $k);
52 |
53 | try {
54 | call_user_func_array(
55 | [$field, $method],
56 | $args
57 | );
58 |
59 | if ($field instanceof MultipleFile && strtolower($method) == 'removable') {
60 |
61 | $id = preg_replace('/^c_(\d+)_/i', '$1', $field->column());
62 |
63 | $field->options(['deleteUrl' => admin_base_path('configx/delfile/' . $id)]);
64 | }
65 |
66 | } catch (\Exception $e) {
67 | admin_warning('Error', "'" . $field->label() . "' call method : " . class_basename($field) . '->' . $method . "('" . implode("','", $args) . "')" . ' failed ! ' . $e->getMessage());
68 | \Log::error($e->__toString());
69 | }
70 | }
71 | }
72 |
73 | return $field;
74 | }
75 |
76 | public static function remove($cx_options)
77 | {
78 | $forget = [];
79 | foreach (array_keys($cx_options) as $k) {
80 | if ($k == '__configx_tabs__') {
81 | continue;
82 | }
83 | $config = ConfigxModel::where('name', $k)->first();
84 | if (!$config) {
85 | $forget[] = $k;
86 | }
87 | if (preg_match('/admin_\d+?/i', $k)) {
88 | $forget[] = $k;
89 | }
90 | }
91 | if (count($forget)) {
92 | Arr::forget($cx_options, $forget);
93 | }
94 | return $cx_options;
95 | }
96 |
97 | public static function sortGroupConfigs($configs, $cx_options = [])
98 | {
99 | $order = [];
100 | $i = 0;
101 | foreach ($configs as $conf) {
102 | $i += 1;
103 | if (isset($cx_options[$conf['name']]) && isset($cx_options[$conf['name']]['order'])) {
104 | $order[] = $cx_options[$conf['name']]['order'] ?: 999 + $i;
105 | } else {
106 | $order[] = 999 + $i;
107 | }
108 | }
109 | array_multisort($order, SORT_ASC, $configs);
110 | return $configs;
111 | }
112 |
113 | public static function sortTGroupOptions($type, $cx_options = [])
114 | {
115 | $subs = ConfigxModel::group($type);
116 |
117 | $subs = static::sortGroupConfigs($subs, $cx_options);
118 |
119 | $i = 0;
120 | foreach ($subs as $sub) {
121 | if (!isset($cx_options[$sub['name']]) || empty($cx_options[$sub['name']])) {
122 | $cx_options[$sub['name']] = [
123 | 'options' => [],
124 | 'element' => 'normal',
125 | 'help' => '',
126 | 'name' => '',
127 | 'order' => 999,
128 | ];
129 | }
130 | if (isset($cx_options[$sub['name']]) && isset($cx_options[$sub['name']]['table_field'])) {
131 | continue;
132 | }
133 | $i += 5;
134 | $cx_options[$sub['name']]['order'] = $i;
135 | }
136 |
137 | return $cx_options;
138 | }
139 |
140 | public static function createTableConfigs($tableInfo, $cx_options = [])
141 | {
142 | if (empty($tableInfo)) {
143 | return $cx_options;
144 | }
145 | foreach ($tableInfo as $k => $v) {
146 | if ($k == $v || '' == $v) {
147 | $conf = ConfigxModel::where('name', $k)->first();
148 | if (!$conf) {
149 | ConfigxModel::create(['name' => $k, 'value' => '1', 'description' => 'Table field:' . $k]);
150 | }
151 | }
152 | if (!isset($cx_options[$k])) {
153 | $cx_options[$k] = ['element' => 'normal', 'options' => [], 'help' => '', 'name' => '', 'order' => 999];
154 | }
155 | if ($k == $v || '' == $v) {
156 | $cx_options[$k]['table_field'] = 1;
157 | } else {
158 | if (isset($cx_options[$k]['table_field'])) {
159 | array_forget($cx_options[$k], 'table_field');
160 | }
161 | }
162 | }
163 |
164 | return $cx_options;
165 | }
166 |
167 | public static function checkTableKeys($mainKey, $tableInfo)
168 | {
169 | if (empty($tableInfo)) {
170 | return [];
171 | }
172 |
173 | $_tableInfo = [];
174 | foreach ($tableInfo as $k => $v) {
175 | $newKey = $mainKey . preg_replace('/.+(_\d+_\d+)$/', '$1', $k);
176 |
177 | $_tableInfo[$newKey] = $v;
178 | }
179 |
180 | return $_tableInfo;
181 | }
182 |
183 | public static function createPermissions($tabs)
184 | {
185 | foreach ($tabs as $key => $val) {
186 | ConfigxModel::createPermission($key, $val);
187 | }
188 | }
189 |
190 | public static function checkPermission()
191 | {
192 | return Configx::config('check_permission', false);
193 | }
194 |
195 | public static function tabs($cx_options = [])
196 | {
197 | $tabs = Configx::config('tabs', ['base' => 'Base']);
198 |
199 | if (isset($cx_options['__configx_tabs__']) && isset($cx_options['__configx_tabs__']['options'])) {
200 | $tabs = !empty($cx_options['__configx_tabs__']['options']) ? $cx_options['__configx_tabs__']['options'] : $tabs;
201 | }
202 |
203 | foreach ($tabs as $key => &$value) {
204 |
205 | if (empty($value)) {
206 | $value = trans('admin.configx.tabs.' . $key); // if tab name is empty , get from trans
207 | }
208 | }
209 |
210 | return $tabs;
211 | }
212 |
213 | public static function prepareUpdate($fields, $data)
214 | {
215 | $prepared = [];
216 |
217 | foreach ($fields as $field) {
218 | $columns = $field->column();
219 |
220 | if (!Arr::has($data, $columns)) {
221 | continue;
222 | }
223 |
224 | $value = static::getDataByColumn($data, $field->column());
225 |
226 | $value = $field->prepare($value);
227 |
228 | if (is_array($columns)) {
229 |
230 | $key = array_values($columns)[0];
231 |
232 | Arr::set($prepared, $key, implode(',', array_filter(array_values($value))));
233 | } elseif (is_string($columns)) {
234 |
235 | if ($field instanceof MultipleFile) {
236 |
237 | $value = implode(',', $value);
238 | } else if ($field instanceof MultipleSelect) {
239 |
240 | $value = implode(',', $value);
241 | }
242 |
243 | Arr::set($prepared, $columns, $value);
244 | }
245 | }
246 |
247 | return $prepared;
248 | }
249 |
250 | /**
251 | * Merge validation messages from input validators.
252 | *
253 | * @param \Illuminate\Validation\Validator[] $validators
254 | *
255 | * @return MessageBag
256 | */
257 | public static function mergeValidationMessages($validators)
258 | {
259 | $messageBag = new MessageBag();
260 |
261 | foreach ($validators as $validator) {
262 | $messageBag = $messageBag->merge($validator->messages());
263 | }
264 |
265 | return $messageBag;
266 | }
267 | /**
268 | * @param array $data
269 | * @param string|array $columns
270 | *
271 | * @return array|mixed
272 | */
273 | public static function getDataByColumn($data, $columns)
274 | {
275 |
276 | if (is_string($columns)) {
277 |
278 | return Arr::get($data, $columns);
279 | }
280 |
281 | if (is_array($columns)) {
282 | $value = [];
283 | foreach ($columns as $name => $column) {
284 | if (!Arr::has($data, $column)) {
285 | continue;
286 | }
287 | $value[$name] = Arr::get($data, $column);
288 | }
289 |
290 | return $value;
291 | }
292 | }
293 |
294 | public static function getConfigx()
295 | {
296 | $__configx__ = ConfigxModel::where('name', '__configx__')->first();
297 |
298 | if ($__configx__) {
299 | return $__configx__;
300 | }
301 |
302 | return ConfigxModel::create(['name' => '__configx__', 'description' => '', 'value' => 'do not delete']);
303 | }
304 |
305 | }
306 |
--------------------------------------------------------------------------------
/resources/views/tips.blade.php:
--------------------------------------------------------------------------------
1 | Help
2 |
3 |
Use texts
4 |
5 | text1
6 | text2
7 | ...
8 |
9 | Or key-texts
10 |
11 | key1 : text1
12 | key2 : text2
13 | ...
14 |
15 |
16 |
17 | Or load data from url:
18 |
19 | //Options:
20 | options_url : /admin/api/mydata
21 | //Or methods:
22 | @options : /admin/api/mydata
23 |
24 |
25 |
26 |
27 | //Options:
28 | rows : 5
29 | //Or methods:
30 | @rows : 5
31 |
32 |
33 |
34 |
35 | //Options:
36 | max : 100
37 | min : 1
38 | //Or methods:
39 | @max : 100
40 | @min : 1
41 |
42 |
43 |
44 |
editor_name : editor
45 |
46 |
47 |
48 | //Options:
49 | format : rgba
50 | //color format can be : [hex, rgb, rgba]
51 | //Or methods:
52 | @hex
53 | @rgb
54 | @rgba
55 |
56 |
57 |
58 |
59 | Common options:
60 |
61 | divide : after
62 | //<hr> befor or after this element.
63 | rules : required|min:3|max:12
64 |
65 | Common Methods:
66 |
67 | @rules : required|min:3|max:12
68 | @setWidth : 6, 2
69 | //etc..
70 | //@methodname : arg1, arg2 ...
71 | //suported args types [string/integer/folat/boolean]
72 |
73 |
74 |
75 | Replace default element:
76 |
77 | __element__ : mobile
78 | //__element__ : ip
79 | //__element__ : url
80 | //__element__ : email
81 | //__element__ : currency
82 | //etc..
83 |
84 | Extend element:
85 |
86 | __element__ : test_text
87 |
88 | //Extend element in Admin/bootstrap.php :
89 | Form::extend('new_element', App/Admin/Extensions/NewElement::class);
90 | //Useage
91 | __element__ : new_element
92 |
93 |
94 |
95 | //Image Methods:
96 |
97 | @uniqueName
98 | @sequenceName
99 | @removable
100 | @move : newdir, newname
101 | @dir : newdir
102 | @name : newname
103 | @resize : 320, 240
104 | @insert : storage/public/watermark.png ,center
105 | @crop : 320, 240, 0, 0
106 | //etc..
107 |
108 | //Some methods require intervention/image
[installation]
109 |
110 | //Usage :
[Intervention]
111 |
112 |
113 | //File Methods:
114 |
115 | @uniqueName
116 | @sequenceName
117 | @removable
118 | @downloadable
119 | @retainable
120 | //multiple
121 | @sortable
122 | @move : newdir, newname
123 | @dir : newdir
124 | @name : newname
125 | //etc..
126 |
127 |
128 |
129 |
130 | //To use map ,you need to edit configs first.
131 | //map_provider in /config/admin.php
132 | //TENCENT_MAP_API_KEY or GOOGLE_API_KEY in /.env
133 |
134 |
135 |
136 |
137 | rows : 3
138 | cols : 3
139 |
140 |
Build table
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
309 |
--------------------------------------------------------------------------------
/src/Tools/Updater.php:
--------------------------------------------------------------------------------
1 | 0) {
31 | admin_toastr(trans('admin.update_succeeded'));
32 | return redirect()->to(admin_base_path('configx/edit/' . $id) . '?do=new_config');
33 | } else {
34 | admin_toastr(trans('admin.save_succeeded'));
35 | return redirect()->to(admin_base_path('configx/edit/0') . '?do=new_config');
36 | }
37 | }
38 |
39 | public static function saveTabsOptions($id = 0, $tabs_options)
40 | {
41 | $cx_options = static::cxOptions();
42 |
43 | $c_options = explode(PHP_EOL, $tabs_options);
44 | $arr = [];
45 | foreach ($c_options as $op) {
46 | $kv = explode(":", $op);
47 | if (empty($kv[0])) {
48 | continue;
49 | }
50 | if (count($kv) > 1) {
51 | $arr[trim($kv[0])] = trim($kv[1]);
52 | } else {
53 | $arr[trim($kv[0])] = '';
54 | }
55 | }
56 | $cx_options['__configx_tabs__']['options'] = $arr;
57 |
58 | static::cxSave($cx_options);
59 |
60 | admin_toastr(trans('admin.save_succeeded'));
61 |
62 | Session::put('tabindex', '0');
63 |
64 | return redirect()->to(admin_base_path('configx/edit/' . $id) . '?do=tabs_config');
65 | }
66 |
67 | public static function saveConfigs($id = 0, $request)
68 | {
69 | $cx_options = static::cxOptions();
70 |
71 | $tabs = Tool::tabs($cx_options);
72 |
73 | Session::put('tabindex', $request->input('tabindex', 0));
74 |
75 | Tree::getConfigTabs($tabs, $cx_options);
76 |
77 | $rootConfigs = array_values(Tree::getTree());
78 |
79 | $data = $request->all();
80 |
81 | $failedValidators = [];
82 |
83 | $fields = [];
84 |
85 | foreach ($rootConfigs as $root) {
86 |
87 | foreach ($root as $val) {
88 |
89 | $field = Builder::getConfigField($cx_options, $val, Builder::UPDATE);
90 |
91 | $fields[] = $field;
92 |
93 | if ($field instanceof Collect) {
94 | $subFields = $field->getFields();
95 |
96 | foreach ($subFields as $sub) {
97 |
98 | if ($sub instanceof MultipleFile) {
99 |
100 | $sub->setOriginal([$sub->column() => explode(',', $val['value'])]);
101 | }
102 |
103 | $fields[] = $sub;
104 | }
105 | } else if ($field instanceof MultipleFile) {
106 |
107 | $field->setOriginal([$field->column() => explode(',', $val['value'])]); // fiels = old + new uploads, suport
108 | }
109 |
110 | $validator = $field->getValidator($data);
111 |
112 | if ($validator && ($validator instanceof Validator) && !$validator->passes()) {
113 |
114 | $errors[] = $val['name'];
115 |
116 | $failedValidators[] = $validator;
117 | }
118 | }
119 | }
120 |
121 | $data = static::handleFileSort($data);
122 |
123 | $prepare = Tool::prepareUpdate($fields, $data);
124 |
125 | $message = Tool::mergeValidationMessages($failedValidators);
126 |
127 | if(!(Configx::config('break_when_errors', false) && $message->any()))
128 | {
129 | admin_toastr(trans('admin.update_succeeded'));
130 | \DB::beginTransaction();
131 |
132 | foreach ($prepare as $column => $value) {
133 |
134 | static::saveValue($column, $value);
135 | }
136 |
137 | static::cxSave($cx_options);
138 |
139 | \DB::commit();
140 | }
141 |
142 | if ($message->any()) {
143 |
144 | static::getErrorIndex($errors[0], $failedValidators[0]->messages()->first(), $cx_options);
145 |
146 | return redirect()->to(admin_base_path('configx/edit/' . $id))->withErrors($message->getMessages())->withInput();
147 | }
148 |
149 | return redirect()->to(admin_base_path('configx/edit/' . $id));
150 | }
151 |
152 | /**
153 | * @param array $input
154 | *
155 | * @return array
156 | */
157 | protected static function handleFileSort($input = [])
158 | {
159 | if (!array_key_exists(Field::FILE_SORT_FLAG, $input)) {
160 | return $input;
161 | }
162 |
163 | $sorts = array_filter($input[Field::FILE_SORT_FLAG]);
164 |
165 | if (empty($sorts)) {
166 | return $input;
167 | }
168 |
169 | foreach ($sorts as $column => $order) {
170 | $input[$column] = $order;
171 | }
172 |
173 | request()->replace($input);
174 |
175 | return $input;
176 | }
177 |
178 | protected static function getErrorIndex($first, $msg, $cx_options)
179 | {
180 | admin_warning('Error', $msg);
181 |
182 | $tabs = Tool::tabs($cx_options);
183 | $tab = explode('.', $first);
184 | if (count($tabs) && count($tab)) {
185 | $errorKey = $tab[0];
186 | $i = 0;
187 | foreach ($tabs as $k => $v) {
188 | if ($k == $errorKey) {
189 | Session::put('tabindex', $i);
190 | break;
191 | }
192 | $i += 1;
193 | }
194 | }
195 | }
196 |
197 | protected static function saveValue($columns, $value)
198 | {
199 | if ($value == null || $value == '') {
200 | return;
201 | }
202 |
203 | $key = $columns;
204 |
205 | if (is_array($columns)) {
206 |
207 | $key = array_values($columns)[0];
208 | }
209 |
210 | $id = preg_replace('/^c_(\d+)_/i', '$1', $key);
211 |
212 | $config = ConfigxModel::findOrFail($id);
213 |
214 | $config->value = $value;
215 | $config->update();
216 | }
217 |
218 | public static function saveOptions($id = 0, $cx_options, Request $request)
219 | {
220 | if (empty($request->values['c_type']) || empty($request->values['c_key'])) {
221 | admin_warning('Error', trans('admin.input') . ' ' . trans('admin.configx.new_config_type') . ' / ' . trans('admin.configx.new_config_key'));
222 | return redirect()->back()->withInput();
223 | }
224 | $config = [];
225 | $defaultVal = "1";
226 | if ($id > 0) {
227 | $config = ConfigxModel::findOrFail($id);
228 | $new_key = $config['name'];
229 | } else {
230 | $new_key = $request->values['c_key'];
231 | if (!preg_match('/^' . $request->values['c_type'] . '\.\w{1,}/', $new_key)) {
232 | $new_key = $request->values['c_type'] . '.' . $new_key;
233 | }
234 | if (ConfigxModel::where('name', $new_key)->first()) {
235 | admin_warning('Error', "The key `{$new_key}` exists in table.");
236 | return redirect()->back()->withInput();
237 | }
238 | if ($request->values['c_element'] == "date") {
239 | $defaultVal = "2019-01-01";
240 | } else if ($request->values['c_element'] == "datetime") {
241 | $defaultVal = "2019-01-01 01:01:01";
242 | } else if ($request->values['c_element'] == "icon") {
243 | $defaultVal = "fa-code";
244 | } else if ($request->values['c_element'] == "color") {
245 | $defaultVal = "#ccc";
246 | } else if ($request->values['c_element'] == "multiple_image") {
247 | $defaultVal = '-';
248 | }
249 | }
250 | if (!isset($cx_options[$new_key]) || empty($cx_options[$new_key])) {
251 | $cx_options[$new_key] = [
252 | 'options' => [],
253 | 'element' => 'normal',
254 | 'help' => '',
255 | 'name' => '',
256 | 'order' => 999,
257 | ];
258 | }
259 | $table_field = isset($cx_options[$new_key]['table_field']);
260 | $order = Arr::get($cx_options[$new_key], 'order', 999);
261 | if (!empty($request->values['c_options'])) {
262 | $c_options = explode(PHP_EOL, $request->values['c_options']);
263 | $arr = [];
264 | foreach ($c_options as $op) {
265 | $kv = explode(":", $op);
266 | if (empty($kv[0])) {
267 | continue;
268 | }
269 | if (count($kv) == 2) {
270 | $arr[trim($kv[0])] = trim($kv[1]);
271 | } else if (count($kv) > 2) {
272 | $values = array_slice($kv, 1);
273 | $arr[trim($kv[0])] = trim(implode(':', $values));
274 | } else {
275 | $arr[trim($kv[0])] = trim($kv[0]);
276 | }
277 | }
278 | $cx_options[$new_key] = ['options' => $arr, 'element' => $request->values['c_element'], 'help' => $request->values['c_help'], 'name' => $request->values['c_name'], 'order' => 999];
279 | $keys = array_keys($arr);
280 | if ($request->values['c_element'] == "table") {
281 | $defaultVal = 'do not delete';
282 | } else if (in_array(
283 | $request->values['c_element'],
284 | ['radio_group', 'checkbox_group', 'select', 'multiple_select', 'listbox']
285 | ) && $keys) {
286 | $defaultVal = $keys[0];
287 | }
288 | } else {
289 | if (in_array($request->values['c_element'], ['radio_group', 'checkbox_group', 'select', 'table', 'multiple_select', 'listbox'])) {
290 | admin_warning('Error', "The options is empty!");
291 | return redirect()->back()->withInput();
292 | } else {
293 | $cx_options[$new_key] = ['options' => [], 'element' => $request->values['c_element'], 'help' => $request->values['c_help'], 'name' => $request->values['c_name'], 'order' => 999];
294 | }
295 | }
296 | if ($request->values['c_element'] == 'table' && empty($request->table)) {
297 | admin_warning('Error', "Build table befor save!");
298 | return redirect()->back()->withInput();
299 | }
300 | if ($id == 0) {
301 | if (preg_match('/\$admin\$/i', $new_key)) {
302 | $defaultVal = 'do not delete';
303 | }
304 | $data = ['name' => $new_key, 'value' => $defaultVal, 'description' => $request->values['c_name'] ?: trans('admin.configx.' . $new_key)];
305 | if ($request->values['c_element'] == "table") {
306 | $table = Tool::checkTableKeys($new_key, $request->table);
307 | $cx_options = Tool::createTableConfigs($table, $cx_options);
308 | $data['description'] = json_encode($table);
309 | }
310 | $config = new ConfigxModel($data);
311 | $config->save();
312 | $c_type = $request->values['c_type'];
313 | } else {
314 | $data = ['name' => $new_key];
315 | if ($request->values['c_element'] == "table") {
316 | $table = Tool::checkTableKeys($new_key, $request->table);
317 | $cx_options = Tool::createTableConfigs($table, $cx_options);
318 | $data['description'] = json_encode($table);
319 | }
320 | $config->update($data);
321 | $c_type = $config->getPrefix();
322 | }
323 | $tabs = Tool::tabs($cx_options);
324 | if (count($tabs)) {
325 | $i = 0;
326 | foreach ($tabs as $k => $v) {
327 | if ($k == $c_type) {
328 | Session::put('tabindex', $i);
329 | break;
330 | }
331 | $i += 1;
332 | }
333 | }
334 | if ($table_field) {
335 | $cx_options[$new_key]['table_field'] = 1;
336 | }
337 | if ($order) {
338 | $cx_options[$new_key]['order'] = $order;
339 | }
340 |
341 | $cx_options = Tool::sortTGroupOptions($c_type, $cx_options);
342 |
343 | return $cx_options;
344 | }
345 |
346 | protected static function cxOptions()
347 | {
348 | $__configx__ = Tool::getConfigx();
349 |
350 | $cx_options = [];
351 |
352 | if ($__configx__ && $__configx__['description']) {
353 |
354 | $cx_options = json_decode($__configx__['description'], 1);
355 | }
356 |
357 | return $cx_options;
358 | }
359 |
360 | protected static function cxSave($cx_options)
361 | {
362 | $__configx__ = Tool::getConfigx();
363 |
364 | $cx_options = Tool::remove($cx_options);
365 | $__configx__['description'] = json_encode($cx_options);
366 | $__configx__->save();
367 | }
368 | }
369 |
--------------------------------------------------------------------------------
/src/Tools/Builder.php:
--------------------------------------------------------------------------------
1 | [],
26 | 'element' => 'normal',
27 | 'help' => '',
28 | 'name' => '',
29 | 'order' => 999,
30 | ];
31 | }
32 |
33 | $field = static::getConfigField($cx_options, $val, static::EDIT);
34 |
35 | if (in_array($val['id'], ['type', 'key', 'element'])) {
36 | $field->setLabelClass(['asterisk']);
37 | }
38 |
39 | if (isset($cx_options[$val['name']]['options'])) {
40 | $options = Arr::get($cx_options[$val['name']], 'options', []);
41 | if (isset($options['divide'])) {
42 | if ($options['divide'] == 'befor') {
43 | return ' ' . $field->render();
44 | } else {
45 | return $field->render() . ' ';
46 | }
47 | }
48 | }
49 | return $field->render();
50 | }
51 |
52 | public static function createNewConfigForm($val, $tabs, $cx_options = [], $config = [])
53 | {
54 | if (!isset($cx_options[$val['name']])) {
55 | $cx_options[$val['name']] = [];
56 | }
57 |
58 | $label = trans('admin.configx.' . $val['name']);
59 |
60 | if ($config) {
61 | $editName = $config['name'];
62 | }
63 |
64 | $rowname = 'values.c_' . $val['id'];
65 |
66 | if ($val['id'] == 'type') {
67 | if ($config) {
68 | $field = new Text($rowname, [$label]);
69 | $field->readOnly();
70 | $typekey = explode('.', $editName)[0];
71 | $typename = Arr::get($tabs, $typekey);
72 | if (empty($typename)) {
73 | $typename = trans('admin.configx.tabs.' . $typekey); // if tab name is empty , get from trans
74 | }
75 | if (isset($cx_options[$config['name']]['table_field'])) {
76 | $tableKey = preg_replace('/^(\w+?\.\w+?)_\d+_\d+$/i', '$1', $editName);
77 | if ($cx_options && isset($cx_options[$tableKey]) && isset($cx_options[$tableKey]['name'])) {
78 | $typename .= '-' . $cx_options[$tableKey]['name'];
79 | } else {
80 | $typename .= '-' . trans('admin.configx.' . $tableKey);
81 | }
82 | }
83 | $field->value($typename);
84 | //
85 | } else {
86 | $field = new Radio($rowname, [$label]);
87 |
88 | $field->options($tabs)
89 | ->setWidth(9, 2);
90 | }
91 | } else if ($val['id'] == 'key' || $val['id'] == 'tabs_key') {
92 | $field = new Text($rowname, [$label]);
93 |
94 | if ($val['id'] == 'tabs_key') {
95 | $field->value('__configx_tabs__');
96 | $field->readOnly();
97 | } else {
98 | if ($config) {
99 | $field->readOnly();
100 | $field->value($editName);
101 | }
102 | }
103 | } else if ($val['id'] == 'name') {
104 | $field = new Text($rowname, [$label]);
105 | if ($config) {
106 | if ($config && isset($cx_options[$config['name']]['name'])) {
107 | $field->value($cx_options[$config['name']]['name']);
108 | }
109 | }
110 | } else if ($val['id'] == 'element') {
111 | $field = new Radio($rowname, [$label]);
112 | $elements = [
113 | 'normal', 'date', 'time', 'datetime', 'image', 'multiple_image', 'password', 'file', 'multiple_file',
114 | 'yes_or_no', 'rate', 'editor', 'tags', 'icon', 'color', 'number', 'table', 'textarea',
115 | 'radio_group', 'checkbox_group', 'listbox', 'select', 'multiple_select', 'map',
116 | ];
117 | if ($config && isset($cx_options[$config['name']]['table_field'])) {
118 | array_delete($elements, 'table');
119 | }
120 | $support = [];
121 | foreach ($elements as $el) {
122 | $support[$el] = trans('admin.configx.element.' . $el);
123 | }
124 | $field->options($support)
125 | ->default('normal')
126 | ->setWidth(9, 2);
127 | if ($config && isset($cx_options[$config['name']]['element'])) {
128 | $field->value($cx_options[$config['name']]['element']);
129 | }
130 | } else if ($val['id'] == 'help') {
131 | $field = new Text($rowname, [$label]);
132 | if ($config && isset($cx_options[$config['name']]['help'])) {
133 | $field->value($cx_options[$config['name']]['help']);
134 | }
135 | } else if ($val['id'] == 'options' || $val['id'] == 'tabs_options') {
136 | $field = new Textarea($rowname, [$label]);
137 | $table = \Request::old('table');
138 | if (
139 | !$table && $config && isset($cx_options[$config['name']]['element'])
140 | && $cx_options[$config['name']]['element'] == 'table'
141 | && $config['description']
142 | ) {
143 | $table = json_decode($config['description']);
144 | }
145 | if ($val['id'] == 'options') {
146 | $field->help(view('configx::tips', ['table' => $table]));
147 | if ($config && isset($cx_options[$config['name']]['options'])) {
148 | $arr = [];
149 | foreach ($cx_options[$config['name']]['options'] as $k => $v) {
150 | if ($k == $v) {
151 | $arr[] = $k;
152 | } else {
153 | $arr[] = $k . ' : ' . $v;
154 | }
155 | }
156 | $field->value(implode(PHP_EOL, $arr));
157 | }
158 | } else {
159 | $field->help(view('configx::tabs'));
160 | $tabs = Configx::config('tabs', ['base' => 'Base']);
161 | if (isset($cx_options['__configx_tabs__']) && isset($cx_options['__configx_tabs__']['options'])) {
162 | $tabs = !empty($cx_options['__configx_tabs__']['options']) ? $cx_options['__configx_tabs__']['options'] : $tabs;
163 | }
164 | $arr = [];
165 | foreach ($tabs as $k => $v) {
166 | $arr[] = $k . ' : ' . $v;
167 | }
168 | $field->value(implode(PHP_EOL, $arr));
169 | }
170 |
171 | $field->rows(5);
172 | }
173 |
174 | if (in_array($val['id'], ['type', 'key', 'element'])) {
175 | $field->setLabelClass(['asterisk']);
176 | }
177 |
178 | $field->setWidgetForm(Displayer::getFormWgt());
179 |
180 | return $field->render();
181 | }
182 |
183 | public static function getConfigField($cx_options = [], $val, $mode)
184 | {
185 | $rowname = 'c_' . $val['id'] . '_';
186 |
187 | if (!isset($cx_options[$val['name']]) || empty($cx_options[$val['name']])) {
188 | $cx_options[$val['name']] = [
189 | 'options' => [],
190 | 'element' => 'normal',
191 | 'help' => '',
192 | 'name' => '',
193 | 'order' => 999,
194 | ];
195 | }
196 |
197 | $label = Arr::get($cx_options[$val['name']], 'name', '');
198 | if (!$label) {
199 | $label = trans('admin.configx.' . $val['name']);
200 | }
201 |
202 | if (!key_exists($val['name'], $cx_options)) {
203 | $cx_options[$val['name']] = [];
204 | }
205 |
206 | $etype = Arr::get($cx_options[$val['name']], 'element', 'normal');
207 | $options = Arr::get($cx_options[$val['name']], 'options', []);
208 |
209 | //create field
210 | if ($etype == 'table') {
211 | if (
212 | $val['description'] && isset($options['rows'])
213 | && isset($options['cols'])
214 | ) {
215 | $field = static::buildTable($val, $label, $options, $cx_options, $mode);
216 | } else {
217 | $field = new html('Table error cols and rows is required.', [$label]);
218 | }
219 | return $field;
220 | }
221 |
222 | $trueType = static::trueType($etype, $options);
223 |
224 | if ($etype == 'map') {
225 | $field = static::findField($trueType, $rowname . 'lat', [$rowname . 'lng', $label]);
226 | } else {
227 | $field = static::findField($trueType, $rowname, [$label]);
228 | }
229 |
230 | if (!$field) {
231 | if ($etype == 'editor') {
232 | $field = new Textarea($rowname, [$label]);
233 | } else {
234 | $field = new Text($rowname, [$label]);
235 | }
236 |
237 | $msg = '';
238 |
239 | if ($etype == 'editor') {
240 |
241 | $msg = 'editor[' . Arr::get($options, 'editor_name', 'editor') . ']';
242 |
243 | } else if ($etype == 'normal') {
244 |
245 | $msg = '[' . Arr::get($options, '__element__', 'text') . ']';
246 | } else {
247 | $msg = '[' . $etype . ']';
248 | }
249 |
250 | $field->help('The ' . $msg . ' is unuseable! ');
251 |
252 | unset($cx_options[$val['name']]['help']);
253 |
254 | $options = [];
255 | }
256 |
257 | //init field
258 | if ($etype == 'textarea') {
259 |
260 | if (isset($options['rows'])) {
261 | $field->rows($options['rows']);
262 | }
263 | } else if ($etype == 'yes_or_no') {
264 |
265 | $field->options(['1' => trans('admin.yes'), '0' => trans('admin.no')]);
266 | } else if ($etype == 'number') {
267 |
268 | if (isset($options['max'])) {
269 | $field->max($options['max']);
270 | }
271 | if (isset($options['min'])) {
272 | $field->min($options['min']);
273 | }
274 | } else if (in_array($etype, ['radio_group', 'checkbox_group', 'listbox', 'select', 'multiple_select'])) {
275 |
276 | if (in_array($etype, ['select', 'multiple_select']) && isset($options['options_url'])) {
277 | $field->options($options['options_url']);
278 | } else {
279 | $field->options(Tool::optionsFilter($options));
280 | }
281 | } else if ($etype == 'color') {
282 |
283 | if (isset($options['format'])) {
284 | $field->options(['format' => $options['format']]);
285 | }
286 | }
287 | if (isset($options['rules'])) {
288 | $field->rules($options['rules']);
289 | }
290 | $field->setWidgetForm(Displayer::getFormWgt());
291 | // fill value
292 |
293 | if ($mode == static::EDIT) {
294 | static::fillData($field, $etype, $rowname, $val['value']);
295 | }
296 |
297 | if (isset($cx_options[$val['name']]['help']) && !empty($cx_options[$val['name']]['help'])) {
298 | $field->help($cx_options[$val['name']]['help']);
299 | }
300 |
301 | if ($options) {
302 |
303 | $field = Tool::callUserfunctions($field, $options);
304 |
305 | if (!in_array($etype, ['image', 'file', 'multiple_image', 'multiple_file'])) {
306 |
307 | if ($mode == static::UPDATE) {
308 | $field->rules('required');
309 | }
310 | }
311 |
312 | } else {
313 |
314 | if (in_array($etype, ['image', 'file', 'multiple_image', 'multiple_file'])) {
315 |
316 | $field->uniqueName();
317 | } else {
318 | if ($mode == static::UPDATE) {
319 | $field->rules('required');
320 | }
321 | }
322 | }
323 |
324 | return $field;
325 | }
326 |
327 | protected static function fillData($field, $etype, $rowname, $value)
328 | {
329 | $columns = $field->column();
330 |
331 | if (is_array($columns)) {
332 |
333 | $values = explode(',', $value);
334 |
335 | $data = [];
336 |
337 | $i = 0;
338 | foreach ($columns as $name => $column) {
339 | $data[$column] = Arr::get($values, $i, '-');
340 | $i += 1;
341 | }
342 |
343 | $field->fill($data);
344 |
345 | } else if (in_array($etype, ['checkbox_group', 'multiple_select', 'listbox', 'multiple_image', 'multiple_file'])) {
346 | $values = array_filter(explode(',', $value));
347 |
348 | if ($value && count($values)) {
349 | $field->value($values);
350 | }
351 | } else {
352 | $field->fill([$rowname => $value]);
353 | }
354 | }
355 |
356 | protected static function buildTable($val, $label, $options, $cx_options, $mode)
357 | {
358 | $tableInfo = json_decode($val['description'], 1);
359 | if ($tableInfo) {
360 | Tool::createTableConfigs($tableInfo, $cx_options);
361 | }
362 | $field = new Table($label);
363 | $rows = [];
364 | for ($i = 0; $i < $options['rows']; $i += 1) {
365 | $tableRow = new TableRow();
366 | for ($j = 0; $j < $options['cols']; $j += 1) {
367 | $fieldKey = $val['name'] . '_' . $i . '_' . $j;
368 | if (!key_exists($fieldKey, $tableInfo)) {
369 | continue;
370 | }
371 | if ($tableInfo[$fieldKey] == $fieldKey || '' == $tableInfo[$fieldKey]) {
372 |
373 | $conf = ConfigxModel::where('name', $fieldKey)->first();
374 | if ($conf) {
375 |
376 | $etype = Arr::get($cx_options[$conf['name']], 'element', 'normal');
377 |
378 | if ($etype == 'normal' && $options['cols'] > 8) {
379 | Arr::set($cx_options[$conf['name']], 'element', 'textSmall');
380 | }
381 |
382 | if (!isset($cx_options[$conf['name']])) {
383 | $cx_options[$conf['name']] = [
384 | 'options' => [],
385 | 'element' => 'normal',
386 | 'help' => '',
387 | 'name' => '',
388 | 'order' => 999,
389 | ];
390 | }
391 |
392 | $tableField = static::getConfigField($cx_options, $conf, $mode);
393 |
394 | $tableRow->pushField($tableField, 1);
395 | }
396 | } else {
397 | $text = $tableInfo[$fieldKey];
398 | if (preg_match('/^trans\.(\w+)/i', $text, $mchs)) { //if text is trans.sometext , get from trans : trans("admin.configx.{$tab}.{$tablekey}.{$sometext}")
399 | $text = trans("admin.configx.{$val['name']}.{$mchs[1]}");
400 | }
401 | $tableRow->show($text)->Textalign('center');
402 | }
403 | }
404 | $rows[] = $tableRow;
405 | }
406 | $field->setRows($rows);
407 | $field->setErrorKey($val['name']);
408 |
409 | return $field;
410 | }
411 |
412 | protected static function trueType($type, $options = [])
413 | {
414 | $type =trim($type);
415 |
416 | if(empty($type))
417 | {
418 | $type == 'normal';
419 | }
420 |
421 | if ($type == 'editor') {
422 |
423 | $type = Arr::get($options, 'editor_name', 'editor');
424 | } else if ($type == 'normal') {
425 |
426 | $type = Arr::get($options, '__element__', 'text');
427 | } else if ($type == 'radio_group' || $type == 'yes_or_no') {
428 |
429 | $type = 'radio';
430 | } else if ($type == 'checkbox_group') {
431 |
432 | $type = 'checkbox';
433 | } else if ($type == 'multiple_select') {
434 |
435 | $type = 'multipleSelect';
436 | } else if ($type == 'multiple_image') {
437 |
438 | $type = 'multipleImage';
439 | } else if ($type == 'multiple_file') {
440 |
441 | $type = 'multipleFile';
442 | }
443 |
444 | return $type;
445 | }
446 |
447 | protected static function findField($type, $column, $args)
448 | {
449 | if ($className = Form::findFieldClass($type)) {
450 | $element = new $className($column, $args);
451 |
452 | return $element;
453 | }
454 |
455 | return null;
456 | }
457 | }
458 |
--------------------------------------------------------------------------------