@maxisoft/instantcms-mcp 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/__tests__/artifact-tool.test.js +196 -0
  4. package/dist/__tests__/db-tool.test.js +152 -0
  5. package/dist/__tests__/define-tool.test.js +106 -0
  6. package/dist/__tests__/find-tool.test.js +185 -0
  7. package/dist/__tests__/get-component-api.test.js +144 -0
  8. package/dist/__tests__/hardening.test.js +73 -0
  9. package/dist/__tests__/hooks-tool.test.js +173 -0
  10. package/dist/__tests__/mcp-integration-extra.test.js +166 -0
  11. package/dist/__tests__/mcp-integration.test.js +53 -0
  12. package/dist/__tests__/pagination.test.js +114 -0
  13. package/dist/__tests__/performance-baseline.test.js +56 -0
  14. package/dist/__tests__/project-patch.test.js +144 -0
  15. package/dist/__tests__/project-source.test.js +44 -0
  16. package/dist/__tests__/project-workflows-extra.test.js +165 -0
  17. package/dist/__tests__/project-workflows.test.js +51 -0
  18. package/dist/__tests__/scaffold-addon-roundtrip.test.js +287 -0
  19. package/dist/__tests__/serialization.test.js +170 -0
  20. package/dist/__tests__/source-knowledge-parsers.test.js +42 -0
  21. package/dist/__tests__/template-development.test.js +78 -0
  22. package/dist/__tests__/template-productivity.test.js +87 -0
  23. package/dist/__tests__/tools.test.js +2143 -0
  24. package/dist/data/components.js +2818 -0
  25. package/dist/data/controllers-map.js +7571 -0
  26. package/dist/data/core-api.js +9356 -0
  27. package/dist/data/database-schema.js +4555 -0
  28. package/dist/data/events-map.js +1339 -0
  29. package/dist/data/fields-map.js +3692 -0
  30. package/dist/data/hooks.js +2257 -0
  31. package/dist/data/js-api.js +123 -0
  32. package/dist/data/libs-api.js +264 -0
  33. package/dist/data/routes-map.js +203 -0
  34. package/dist/data/schemas-validation.js +255 -0
  35. package/dist/data/schemas.js +1404 -0
  36. package/dist/data/traits-map.js +1004 -0
  37. package/dist/data/version-profiles.js +41 -0
  38. package/dist/data/widgets-map.js +131 -0
  39. package/dist/data/wysiwyg-map.js +486 -0
  40. package/dist/generated/components-source.js +14748 -0
  41. package/dist/generated/hooks-source.js +3399 -0
  42. package/dist/generated/knowledge-meta.js +101 -0
  43. package/dist/index.js +13 -0
  44. package/dist/registry/database-tools.js +112 -0
  45. package/dist/registry/extension-tools.js +473 -0
  46. package/dist/registry/generator-tools.js +506 -0
  47. package/dist/registry/knowledge-tools.js +441 -0
  48. package/dist/registry/language-tools.js +99 -0
  49. package/dist/registry/meta-tools.js +152 -0
  50. package/dist/registry/project-tools.js +48 -0
  51. package/dist/registry/resources.js +98 -0
  52. package/dist/registry/source-tools.js +211 -0
  53. package/dist/registry/template-development-tools.js +79 -0
  54. package/dist/server.js +32 -0
  55. package/dist/tools/addon-tool.js +1437 -0
  56. package/dist/tools/admin-partial-tool.js +498 -0
  57. package/dist/tools/api-tool.js +294 -0
  58. package/dist/tools/artifact-tool.js +95 -0
  59. package/dist/tools/cache-tool.js +360 -0
  60. package/dist/tools/component-tool.js +415 -0
  61. package/dist/tools/controllers-tool.js +125 -0
  62. package/dist/tools/cron-tool.js +197 -0
  63. package/dist/tools/crud-tool.js +659 -0
  64. package/dist/tools/db-tool.js +198 -0
  65. package/dist/tools/email-tool.js +222 -0
  66. package/dist/tools/external-api-tool.js +596 -0
  67. package/dist/tools/filter-tool.js +341 -0
  68. package/dist/tools/form-tool.js +275 -0
  69. package/dist/tools/grid-tool.js +189 -0
  70. package/dist/tools/hooks-tool.js +104 -0
  71. package/dist/tools/import-export-tool.js +548 -0
  72. package/dist/tools/lang-tool.js +251 -0
  73. package/dist/tools/layout-override-tool.js +125 -0
  74. package/dist/tools/layout-tool.js +548 -0
  75. package/dist/tools/maria-tool.js +127 -0
  76. package/dist/tools/mariadb.js +201 -0
  77. package/dist/tools/migration-tool.js +329 -0
  78. package/dist/tools/oauth-tool.js +520 -0
  79. package/dist/tools/parser/components-parser.js +76 -0
  80. package/dist/tools/parser/controllers-parser.js +313 -0
  81. package/dist/tools/parser/core-parser.js +294 -0
  82. package/dist/tools/parser/coverage-generator.js +424 -0
  83. package/dist/tools/parser/events-parser.js +127 -0
  84. package/dist/tools/parser/fields-parser.js +382 -0
  85. package/dist/tools/parser/hooks-parser.js +106 -0
  86. package/dist/tools/parser/sql-parser.js +197 -0
  87. package/dist/tools/parser/traits-parser.js +161 -0
  88. package/dist/tools/parser/widgets-parser.js +150 -0
  89. package/dist/tools/permission-tool.js +348 -0
  90. package/dist/tools/project-patch-tool.js +73 -0
  91. package/dist/tools/project-source-tool.js +188 -0
  92. package/dist/tools/project-workflow-tool.js +186 -0
  93. package/dist/tools/requirement-tool.js +212 -0
  94. package/dist/tools/scaffold-tool.js +815 -0
  95. package/dist/tools/seo-tool.js +412 -0
  96. package/dist/tools/source-tool.js +155 -0
  97. package/dist/tools/template-development-tool.js +271 -0
  98. package/dist/tools/template-overrides-tool.js +294 -0
  99. package/dist/tools/template-productivity-tool.js +319 -0
  100. package/dist/tools/template-tool.js +665 -0
  101. package/dist/tools/test-tool.js +183 -0
  102. package/dist/tools/webhook-tool.js +427 -0
  103. package/dist/tools/widget-tool.js +331 -0
  104. package/dist/tools/wysiwyg-tool.js +137 -0
  105. package/dist/types/scaffold.js +68 -0
  106. package/dist/utils/define-tool.js +37 -0
  107. package/dist/utils/find-tool.js +97 -0
  108. package/dist/utils/mcp-result.js +18 -0
  109. package/dist/utils/pagination.js +27 -0
  110. package/dist/utils/serialization.js +27 -0
  111. package/package.json +94 -0
@@ -0,0 +1,659 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scaffoldCrud = scaffoldCrud;
4
+ function scaffoldCrud(opts) {
5
+ const name = opts.addon_name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
6
+ const Name = name.split('_').map(capitalize).join('');
7
+ const NAME = name.toUpperCase();
8
+ const files = {};
9
+ const ctrl = `package/system/controllers/${name}`;
10
+ files[`${ctrl}/model.php`] = generateModel(name, Name, opts.fields);
11
+ files[`${ctrl}/frontend.php`] = generateFrontend(name, Name);
12
+ files[`${ctrl}/actions/index.php`] = generateActionIndex(name, Name, NAME);
13
+ files[`${ctrl}/actions/view.php`] = generateActionView(name, Name, NAME);
14
+ files[`${ctrl}/actions/add.php`] = generateActionAdd(name, Name, NAME);
15
+ files[`${ctrl}/actions/edit.php`] = generateActionEdit(name, Name, NAME);
16
+ files[`${ctrl}/actions/delete.php`] = generateActionDelete(name, Name);
17
+ if (opts.options?.use_category) {
18
+ files[`${ctrl}/actions/category.php`] = generateActionCategory(name, Name, NAME);
19
+ }
20
+ files[`${ctrl}/backend.php`] = generateBackend(name, Name, NAME);
21
+ files[`${ctrl}/backend/actions/index.php`] = generateBackendIndex(name, Name, NAME);
22
+ files[`${ctrl}/backend/actions/items.php`] = generateBackendItems(name, Name, NAME);
23
+ files[`${ctrl}/backend/actions/items_add.php`] = generateBackendItemsAdd(name, Name, NAME);
24
+ files[`${ctrl}/backend/actions/items_edit.php`] = generateBackendItemsEdit(name, Name, NAME);
25
+ files[`${ctrl}/backend/actions/items_delete.php`] = generateBackendItemsDelete(name, Name);
26
+ files[`${ctrl}/backend/grids/grid_items.php`] = generateGridItems(name, Name, NAME);
27
+ files[`${ctrl}/backend/forms/form_item.php`] = generateFormItem(opts.fields, Name, NAME);
28
+ files[`package/system/languages/ru/controllers/${name}/${name}.php`] = generateLang(name, NAME, opts.fields);
29
+ return {
30
+ addon_name: name,
31
+ addon_class: Name,
32
+ files_count: Object.keys(files).length,
33
+ files,
34
+ structure_notes: [
35
+ `CRUD для контент-типа: ${name}`,
36
+ `backend.php содержит getBackendMenu() + before()`,
37
+ `Используется trait listgrid + trait formItem`,
38
+ `Языковой файл: /system/languages/ru/controllers/${name}/${name}.php`,
39
+ `Таблица: ${name}_items`,
40
+ ],
41
+ options: opts.options || {},
42
+ };
43
+ }
44
+ function capitalize(str) {
45
+ return str.charAt(0).toUpperCase() + str.slice(1);
46
+ }
47
+ function generateModel(name, Name, fields) {
48
+ const basicFields = fields.filter(f => !f.is_system && f.type !== 'text' && f.type !== 'html');
49
+ let modelCode = `<?php
50
+
51
+ class model${Name} extends cmsModel {
52
+
53
+ protected $table = '${name}_items';
54
+
55
+ `;
56
+ if (basicFields.length > 0) {
57
+ modelCode += ` // Геттеры для полей
58
+ `;
59
+ for (const field of basicFields) {
60
+ const methodName = field.name.replace(/_([a-z])/g, (_, l) => l.toUpperCase());
61
+ modelCode += ` public function get${capitalize(methodName)}($value) {
62
+ return $this->filterEqual('${field.name}', $value);
63
+ }
64
+
65
+ `;
66
+ }
67
+ }
68
+ modelCode += ` public function getPublished(int $limit = 10, int $offset = 0): array {
69
+ return $this->filterEqual('is_pub', 1)
70
+ ->orderBy('date_pub', 'desc')
71
+ ->limit($offset, $limit)
72
+ ->get('${name}_items');
73
+ }
74
+
75
+ public function getByUser(int $user_id, int $limit = 10): array {
76
+ return $this->filterEqual('user_id', $user_id)
77
+ ->orderBy('date_pub', 'desc')
78
+ ->limit($limit)
79
+ ->get('${name}_items');
80
+ }
81
+
82
+ public function getCountPublished(): int {
83
+ return (int) $this->filterEqual('is_pub', 1)->getCount('${name}_items');
84
+ }
85
+
86
+ public function getItem($id) {
87
+ return $this->getItemById('${name}_items', $id);
88
+ }
89
+
90
+ public function addItem(array $item) {
91
+ return $this->insert('${name}_items', $item);
92
+ }
93
+
94
+ public function updateItem($id, array $item) {
95
+ return $this->update('${name}_items', $id, $item);
96
+ }
97
+
98
+ public function deleteItem($id) {
99
+ return $this->delete('${name}_items', $id);
100
+ }
101
+
102
+ }`;
103
+ return modelCode;
104
+ }
105
+ function generateFrontend(name, Name) {
106
+ return `<?php
107
+
108
+ class ${name} extends cmsFrontend {
109
+
110
+ protected $useOptions = true;
111
+
112
+ public function run() {
113
+ return $this->redirect(href_to(${Name}::ROUTE_NAME));
114
+ }
115
+
116
+ }
117
+ ${Name}::ROUTE_NAME = '${name}';
118
+ `;
119
+ }
120
+ function generateActionIndex(name, Name, NAME) {
121
+ return `<?php
122
+
123
+ class action${Name}Index extends cmsAction {
124
+
125
+ public function run($page = 1) {
126
+ $perpage = $this->options['perpage'] ?? 10;
127
+
128
+ $total = $this->model->getCountPublished();
129
+ $items = $this->model->getPublished($perpage, ($page - 1) * $perpage);
130
+
131
+ $pagination = cmsPagination::getInstance($total, $perpage, $page);
132
+
133
+ $this->cms_template->setTitle(LANG_${NAME}_TITLE);
134
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_TITLE);
135
+
136
+ return $this->cms_template->render('index', [
137
+ 'items' => $items,
138
+ 'total' => $total,
139
+ 'pagination' => $pagination,
140
+ 'page' => (int) $page,
141
+ 'perpage' => $perpage,
142
+ ]);
143
+ }
144
+
145
+ }`;
146
+ }
147
+ function generateActionView(name, Name, NAME) {
148
+ return `<?php
149
+
150
+ class action${Name}View extends cmsAction {
151
+
152
+ public function run($id = 0, $slug = '') {
153
+ $item = $this->model->getItem((int) $id);
154
+
155
+ if (!$item || !$item['is_pub']) {
156
+ return cmsCore::error404();
157
+ }
158
+
159
+ if ($slug && $slug !== html_uid($item['title'])) {
160
+ return cmsCore::error404();
161
+ }
162
+
163
+ $item = cmsEventsManager::hook('${name}_before_item', $item);
164
+
165
+ $this->cms_template->setTitle($item['title']);
166
+ $this->cms_template->setMetaDescription($item['description'] ?? '');
167
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_TITLE, href_to(${Name}::ROUTE_NAME));
168
+ $this->cms_template->addBreadcrumb($item['title']);
169
+
170
+ return $this->cms_template->render('view', [
171
+ 'item' => $item,
172
+ ]);
173
+ }
174
+
175
+ }`;
176
+ }
177
+ function generateActionAdd(name, Name, NAME) {
178
+ return `<?php
179
+
180
+ class action${Name}Add extends cmsAction {
181
+
182
+ public function run() {
183
+ if (!$this->cms_user->is_logged) {
184
+ return $this->cms_template->render('login_required', [
185
+ 'login_url' => href_to('auth', 'login'),
186
+ ]);
187
+ }
188
+
189
+ $form = $this->getForm('item');
190
+
191
+ $errors = [];
192
+
193
+ if ($this->request->has('submit')) {
194
+ $data = $form->parse($this->request, $errors);
195
+
196
+ if (!$errors) {
197
+ $data['user_id'] = $this->cms_user->id;
198
+ $data['date_pub'] = date("Y-m-d H:i:s");
199
+
200
+ $id = $this->model->addItem($data);
201
+
202
+ cmsEventsManager::hook('${name}_after_add', $id, $data);
203
+
204
+ $this->redirect(href_to(${Name}::ROUTE_NAME, $id));
205
+ }
206
+ }
207
+
208
+ $this->cms_template->setTitle(LANG_${NAME}_ADD);
209
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_TITLE, href_to(${Name}::ROUTE_NAME));
210
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_ADD);
211
+
212
+ return $this->cms_template->render('add', [
213
+ 'form' => $form,
214
+ 'errors' => $errors,
215
+ ]);
216
+ }
217
+
218
+ }`;
219
+ }
220
+ function generateActionEdit(name, Name, NAME) {
221
+ return `<?php
222
+
223
+ class action${Name}Edit extends cmsAction {
224
+
225
+ public function run($id) {
226
+ $item = $this->model->getItem((int) $id);
227
+
228
+ if (!$item) {
229
+ return cmsCore::error404();
230
+ }
231
+
232
+ if ($item['user_id'] !== $this->cms_user->id && !$this->cms_user->is_admin) {
233
+ return cmsCore::error404();
234
+ }
235
+
236
+ $form = $this->getForm('item');
237
+
238
+ $errors = [];
239
+
240
+ if ($this->request->has('submit')) {
241
+ $data = $form->parse($this->request, $errors);
242
+
243
+ if (!$errors) {
244
+ $this->model->updateItem($id, $data);
245
+
246
+ cmsEventsManager::hook('${name}_after_update', $id, $data);
247
+
248
+ $this->redirect(href_to(${Name}::ROUTE_NAME, $id));
249
+ }
250
+ }
251
+
252
+ $this->cms_template->setTitle(LANG_${NAME}_EDIT);
253
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_TITLE, href_to(${Name}::ROUTE_NAME));
254
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_EDIT);
255
+
256
+ return $this->cms_template->render('edit', [
257
+ 'form' => $form,
258
+ 'item' => $item,
259
+ 'errors' => $errors,
260
+ ]);
261
+ }
262
+
263
+ }`;
264
+ }
265
+ function generateActionDelete(name, Name) {
266
+ return `<?php
267
+
268
+ class action${Name}Delete extends cmsAction {
269
+
270
+ public function run($id) {
271
+ $item = $this->model->getItem((int) $id);
272
+
273
+ if (!$item) {
274
+ return cmsCore::error404();
275
+ }
276
+
277
+ if ($item['user_id'] !== $this->cms_user->id && !$this->cms_user->is_admin) {
278
+ return cmsCore::error404();
279
+ }
280
+
281
+ if ($this->request->has('submit')) {
282
+ $this->model->deleteItem($id);
283
+
284
+ cmsEventsManager::hook('${name}_after_delete', $id);
285
+
286
+ $this->redirect(href_to(${Name}::ROUTE_NAME));
287
+ }
288
+
289
+ return $this->cms_template->render('delete', [
290
+ 'item' => $item,
291
+ ]);
292
+ }
293
+
294
+ }`;
295
+ }
296
+ function generateActionCategory(name, Name, NAME) {
297
+ return `<?php
298
+
299
+ class action${Name}Category extends cmsAction {
300
+
301
+ public function run($slug = '') {
302
+ $category = $this->model->getCategoryBySlug($slug);
303
+
304
+ if (!$category) {
305
+ return cmsCore::error404();
306
+ }
307
+
308
+ $page = $this->request->get('page', 1);
309
+ $perpage = $this->options['perpage'] ?? 10;
310
+
311
+ $total = $this->model->getCountByCategory($category['id']);
312
+ $items = $this->model->getByCategory($category['id'], $perpage, ($page - 1) * $perpage);
313
+
314
+ $this->cms_template->setTitle($category['title']);
315
+ $this->cms_template->addBreadcrumb(LANG_${NAME}_TITLE, href_to(${Name}::ROUTE_NAME));
316
+ $this->cms_template->addBreadcrumb($category['title']);
317
+
318
+ return $this->cms_template->render('category', [
319
+ 'category' => $category,
320
+ 'items' => $items,
321
+ 'total' => $total,
322
+ 'page' => (int) $page,
323
+ 'perpage' => $perpage,
324
+ ]);
325
+ }
326
+
327
+ }`;
328
+ }
329
+ function generateBackend(name, Name, NAME) {
330
+ return `<?php
331
+
332
+ class backend${Name} extends cmsBackend {
333
+
334
+ public $useDefaultOptionsAction = true;
335
+ protected $useOptions = true;
336
+
337
+ public function before($action_name) {
338
+ if (!parent::before($action_name)) {
339
+ return false;
340
+ }
341
+ return true;
342
+ }
343
+
344
+ public function getBackendMenu() {
345
+ return [
346
+ [
347
+ 'title' => LANG_${NAME}_CP_ITEMS,
348
+ 'url' => href_to($this->root_url, 'items'),
349
+ 'options' => ['icon' => 'list'],
350
+ ],
351
+ [
352
+ 'title' => LANG_OPTIONS,
353
+ 'url' => href_to($this->root_url, 'options'),
354
+ 'options' => ['icon' => 'cog'],
355
+ ],
356
+ ];
357
+ }
358
+
359
+ }`;
360
+ }
361
+ function generateBackendIndex(name, Name, _NAME) {
362
+ return `<?php
363
+
364
+ class action${Name}Index extends cmsAction {
365
+
366
+ public function run($do = false) {
367
+ if ($do) {
368
+ return $this->runAction('index_' . $do);
369
+ }
370
+
371
+ $stats = [
372
+ 'total' => $this->model->getCount('${name}_items'),
373
+ 'published' => $this->model->getCountPublished(),
374
+ ];
375
+
376
+ return $this->cms_template->render('backend/index', [
377
+ 'stats' => $stats,
378
+ ]);
379
+ }
380
+
381
+ }`;
382
+ }
383
+ function generateBackendItems(name, Name, NAME) {
384
+ return `<?php
385
+
386
+ class action${Name}Items extends cmsAction {
387
+
388
+ use icms\\traits\\controllers\\actions\\listgrid;
389
+
390
+ public function __construct($controller, $params = []) {
391
+ parent::__construct($controller, $params);
392
+
393
+ $this->table_name = '${name}_items';
394
+ $this->grid_name = 'items';
395
+ $this->title = LANG_${NAME}_CP_ITEMS;
396
+
397
+ $this->tool_buttons = [
398
+ [
399
+ 'class' => 'add',
400
+ 'title' => LANG_${NAME}_CP_ADD,
401
+ 'href' => $this->cms_template->href_to('items', 'add'),
402
+ ],
403
+ ];
404
+ }
405
+
406
+ }`;
407
+ }
408
+ function generateBackendItemsAdd(name, Name, NAME) {
409
+ return `<?php
410
+
411
+ class action${Name}ItemsAdd extends cmsAction {
412
+
413
+ use icms\\traits\\controllers\\actions\\formItem;
414
+
415
+ public function __construct($controller, $params = []) {
416
+ parent::__construct($controller, $params);
417
+
418
+ $this->table_name = '${name}_items';
419
+ $this->form_name = 'item';
420
+ $this->success_url = $this->cms_template->href_to('items');
421
+
422
+ $this->title = [
423
+ 'add' => LANG_${NAME}_CP_ADD,
424
+ 'edit' => '{title}',
425
+ ];
426
+
427
+ $this->breadcrumbs = [
428
+ [LANG_${NAME}_CP_ITEMS, $this->cms_template->href_to('items')],
429
+ LANG_${NAME}_CP_ADD,
430
+ ];
431
+
432
+ $this->use_default_tool_buttons = true;
433
+
434
+ $this->default_item = [
435
+ 'is_pub' => 1,
436
+ 'date_pub' => date("Y-m-d H:i:s"),
437
+ ];
438
+ }
439
+
440
+ }`;
441
+ }
442
+ function generateBackendItemsEdit(name, Name, NAME) {
443
+ return `<?php
444
+
445
+ class action${Name}ItemsEdit extends cmsAction {
446
+
447
+ use icms\\traits\\controllers\\actions\\formItem;
448
+
449
+ public function __construct($controller, $params = []) {
450
+ parent::__construct($controller, $params);
451
+
452
+ $this->table_name = '${name}_items';
453
+ $this->form_name = 'item';
454
+ $this->success_url = $this->cms_template->href_to('items');
455
+
456
+ $this->title = [
457
+ 'add' => LANG_${NAME}_CP_ADD,
458
+ 'edit' => '{title}',
459
+ ];
460
+
461
+ $this->breadcrumbs = [
462
+ [LANG_${NAME}_CP_ITEMS, $this->cms_template->href_to('items')],
463
+ LANG_${NAME}_CP_EDIT,
464
+ ];
465
+
466
+ $this->use_default_tool_buttons = true;
467
+ }
468
+
469
+ }`;
470
+ }
471
+ function generateBackendItemsDelete(name, Name) {
472
+ return `<?php
473
+
474
+ class action${Name}ItemsDelete extends cmsAction {
475
+
476
+ use icms\\traits\\controllers\\actions\\delete\\backend;
477
+
478
+ public function __construct($controller, $params = []) {
479
+ parent::__construct($controller, $params);
480
+
481
+ $this->table_name = '${name}_items';
482
+ $this->success_url = $this->cms_template->href_to('items');
483
+ }
484
+
485
+ }`;
486
+ }
487
+ function generateGridItems(name, _Name, _NAME) {
488
+ return `<?php
489
+
490
+ function grid_items($controller) {
491
+ $columns = [
492
+ 'id' => [
493
+ 'title' => 'ID',
494
+ 'width' => 60,
495
+ 'show' => true,
496
+ ],
497
+ 'title' => [
498
+ 'title' => LANG_TITLE,
499
+ 'filter' => 'like',
500
+ 'href' => href_to($controller->root_url, 'items', ['edit', '{id}']),
501
+ ],
502
+ 'date_pub' => [
503
+ 'title' => LANG_DATE_PUB,
504
+ 'width' => 150,
505
+ 'filter' => 'date',
506
+ ],
507
+ 'user_id' => [
508
+ 'title' => LANG_AUTHOR,
509
+ 'width' => 120,
510
+ ],
511
+ 'is_pub' => [
512
+ 'title' => LANG_IS_PUB,
513
+ 'width' => 80,
514
+ 'flag' => true,
515
+ 'flag_toggle' => href_to($controller->root_url, 'toggle_item', ['{id}', '${name}_items', 'is_pub']),
516
+ ],
517
+ ];
518
+
519
+ $actions = [
520
+ [
521
+ 'title' => LANG_EDIT,
522
+ 'icon' => 'pen',
523
+ 'href' => href_to($controller->root_url, 'items', ['edit', '{id}']),
524
+ ],
525
+ [
526
+ 'title' => LANG_DELETE,
527
+ 'class' => 'text-danger',
528
+ 'icon' => 'times-circle',
529
+ 'confirm' => LANG_DELETE_CONFIRM,
530
+ 'href' => href_to($controller->root_url, 'items', ['delete', '{id}']),
531
+ ],
532
+ ];
533
+
534
+ return [
535
+ 'options' => [
536
+ 'is_sortable' => true,
537
+ 'is_filter' => true,
538
+ 'is_pagination' => true,
539
+ 'is_draggable' => false,
540
+ 'order_by' => 'date_pub',
541
+ 'order_to' => 'desc',
542
+ ],
543
+ 'columns' => $columns,
544
+ 'actions' => $actions,
545
+ ];
546
+ }`;
547
+ }
548
+ function generateFormItem(fields, Name, _NAME) {
549
+ let formCode = `<?php
550
+
551
+ class form${Name}Item extends cmsForm {
552
+
553
+ public function init($do) {
554
+
555
+ $is_edit = ($do === 'edit');
556
+
557
+ return [
558
+ 'basic' => [
559
+ 'title' => LANG_CP_BASIC,
560
+ 'type' => 'fieldset',
561
+ 'childs' => [
562
+ new fieldString('title', [
563
+ 'title' => LANG_TITLE,
564
+ 'rules' => [
565
+ ['required'],
566
+ ['max_length', 255],
567
+ ],
568
+ ]),
569
+ `;
570
+ for (const field of fields) {
571
+ if (field.name === 'title' || field.is_system) {
572
+ continue;
573
+ }
574
+ const fieldClass = getFieldClass(field.type);
575
+ const fieldOptions = {
576
+ title: field.title || capitalize(field.name.replace(/_/g, ' ')),
577
+ };
578
+ if (field.type === 'varchar' || field.type === 'text') {
579
+ fieldOptions.rules = [['max_length', 255]];
580
+ }
581
+ if (field.default !== undefined) {
582
+ fieldOptions.default = field.default;
583
+ }
584
+ const optionsStr = JSON.stringify(fieldOptions, null, 6).replace(/"(\w+)":/g, '$1:');
585
+ formCode += ` new ${fieldClass}('${field.name}', ${optionsStr}),
586
+ `;
587
+ }
588
+ formCode += ` new fieldCheckbox('is_pub', [
589
+ 'title' => LANG_IS_PUB,
590
+ 'default' => 1,
591
+ ]),
592
+ new fieldDate('date_pub', [
593
+ 'title' => LANG_DATE_PUB,
594
+ 'default' => date("Y-m-d H:i:s"),
595
+ ]),
596
+ ],
597
+ ],
598
+ ];
599
+ }
600
+
601
+ }`;
602
+ return formCode;
603
+ }
604
+ function getFieldClass(type) {
605
+ const map = {
606
+ varchar: 'fieldString',
607
+ text: 'fieldText',
608
+ html: 'fieldHtml',
609
+ int: 'fieldNumber',
610
+ tinyint: 'fieldNumber',
611
+ decimal: 'fieldNumber',
612
+ float: 'fieldNumber',
613
+ date: 'fieldDate',
614
+ datetime: 'fieldDate',
615
+ timestamp: 'fieldDate',
616
+ select: 'fieldList',
617
+ enum: 'fieldList',
618
+ radio: 'fieldRadio',
619
+ checkbox: 'fieldCheckbox',
620
+ file: 'fieldFile',
621
+ image: 'fieldImage',
622
+ images: 'fieldImages',
623
+ user: 'fieldUser',
624
+ users: 'fieldUsers',
625
+ };
626
+ return map[type] || 'fieldString';
627
+ }
628
+ function generateLang(name, NAME, fields) {
629
+ let lang = `<?php
630
+
631
+ define('LANG_${NAME}_TITLE', '${capitalize(name.replace(/_/g, ' '))}');
632
+ define('LANG_${NAME}_ADD', 'Добавить');
633
+ define('LANG_${NAME}_EDIT', 'Редактировать');
634
+ define('LANG_${NAME}_DELETE', 'Удалить');
635
+ define('LANG_${NAME}_NOT_FOUND', 'Ничего не найдено');
636
+
637
+ define('LANG_${NAME}_CP_TITLE', 'Управление');
638
+ define('LANG_${NAME}_CP_ITEMS', 'Элементы');
639
+ define('LANG_${NAME}_CP_ADD', 'Добавить элемент');
640
+ define('LANG_${NAME}_CP_EDIT', 'Редактирование элемента');
641
+ define('LANG_${NAME}_CP_DELETE', 'Удаление элемента');
642
+
643
+ `;
644
+ for (const field of fields) {
645
+ if (field.is_system) {
646
+ continue;
647
+ }
648
+ const key = `LANG_${NAME}_${field.name.toUpperCase().replace(/_/g, '_')}`;
649
+ const value = field.title || capitalize(field.name.replace(/_/g, ' '));
650
+ lang += `define('${key}', '${value}');
651
+ `;
652
+ }
653
+ lang += `
654
+ define('LANG_${NAME}_PERPAGE', 'Элементов на странице');
655
+ define('LANG_${NAME}_DATE_FROM', 'Дата от');
656
+ define('LANG_${NAME}_DATE_TO', 'Дата до');
657
+ `;
658
+ return lang;
659
+ }