@rglabs/butterfly 2.0.1

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 (117) hide show
  1. package/CLAUDE.md +201 -0
  2. package/README.md +371 -0
  3. package/dist/commands/add.d.ts +23 -0
  4. package/dist/commands/add.js +303 -0
  5. package/dist/commands/code.d.ts +11 -0
  6. package/dist/commands/code.js +72 -0
  7. package/dist/commands/create-object.d.ts +6 -0
  8. package/dist/commands/create-object.js +293 -0
  9. package/dist/commands/create-report.d.ts +6 -0
  10. package/dist/commands/create-report.js +154 -0
  11. package/dist/commands/diff.d.ts +4 -0
  12. package/dist/commands/diff.js +238 -0
  13. package/dist/commands/download.d.ts +4 -0
  14. package/dist/commands/download.js +374 -0
  15. package/dist/commands/layout.d.ts +12 -0
  16. package/dist/commands/layout.js +83 -0
  17. package/dist/commands/record.d.ts +21 -0
  18. package/dist/commands/record.js +483 -0
  19. package/dist/commands/run-poc.d.ts +3 -0
  20. package/dist/commands/run-poc.js +18 -0
  21. package/dist/commands/setup.d.ts +3 -0
  22. package/dist/commands/setup.js +66 -0
  23. package/dist/commands/start-poc.d.ts +3 -0
  24. package/dist/commands/start-poc.js +55 -0
  25. package/dist/commands/sync-docs.d.ts +3 -0
  26. package/dist/commands/sync-docs.js +27 -0
  27. package/dist/commands/translate.d.ts +13 -0
  28. package/dist/commands/translate.js +401 -0
  29. package/dist/commands/upload.d.ts +3 -0
  30. package/dist/commands/upload.js +150 -0
  31. package/dist/commands/workflow-info.d.ts +13 -0
  32. package/dist/commands/workflow-info.js +161 -0
  33. package/dist/components/ConflictResolver.d.ts +12 -0
  34. package/dist/components/ConflictResolver.js +77 -0
  35. package/dist/components/DiffView.d.ts +11 -0
  36. package/dist/components/DiffView.js +101 -0
  37. package/dist/components/DownloadProgress.d.ts +11 -0
  38. package/dist/components/DownloadProgress.js +29 -0
  39. package/dist/components/RecordPreview.d.ts +11 -0
  40. package/dist/components/RecordPreview.js +91 -0
  41. package/dist/components/SetupForm.d.ts +8 -0
  42. package/dist/components/SetupForm.js +56 -0
  43. package/dist/components/UploadProgress.d.ts +13 -0
  44. package/dist/components/UploadProgress.js +42 -0
  45. package/dist/diff/adapters/index.d.ts +8 -0
  46. package/dist/diff/adapters/index.js +18 -0
  47. package/dist/diff/adapters/objectsAdapter.d.ts +13 -0
  48. package/dist/diff/adapters/objectsAdapter.js +177 -0
  49. package/dist/diff/adapters/reportsAdapter.d.ts +14 -0
  50. package/dist/diff/adapters/reportsAdapter.js +212 -0
  51. package/dist/diff/adapters/types.d.ts +19 -0
  52. package/dist/diff/adapters/types.js +2 -0
  53. package/dist/diff/engine.d.ts +19 -0
  54. package/dist/diff/engine.js +57 -0
  55. package/dist/diff/types.d.ts +34 -0
  56. package/dist/diff/types.js +110 -0
  57. package/dist/index.d.ts +3 -0
  58. package/dist/index.js +117 -0
  59. package/dist/types/index.d.ts +18 -0
  60. package/dist/types/index.js +2 -0
  61. package/dist/utils/api.d.ts +85 -0
  62. package/dist/utils/api.js +1031 -0
  63. package/dist/utils/auth.d.ts +4 -0
  64. package/dist/utils/auth.js +22 -0
  65. package/dist/utils/bfySplitter.d.ts +12 -0
  66. package/dist/utils/bfySplitter.js +151 -0
  67. package/dist/utils/docs.d.ts +16 -0
  68. package/dist/utils/docs.js +186 -0
  69. package/dist/utils/errorLogger.d.ts +6 -0
  70. package/dist/utils/errorLogger.js +29 -0
  71. package/dist/utils/files.d.ts +14 -0
  72. package/dist/utils/files.js +772 -0
  73. package/dist/utils/lockManager.d.ts +15 -0
  74. package/dist/utils/lockManager.js +126 -0
  75. package/dist/utils/resourceHandlers.d.ts +50 -0
  76. package/dist/utils/resourceHandlers.js +684 -0
  77. package/dist/utils/resourceMapping.d.ts +32 -0
  78. package/dist/utils/resourceMapping.js +210 -0
  79. package/dist/utils/singleResourceDownload.d.ts +14 -0
  80. package/dist/utils/singleResourceDownload.js +261 -0
  81. package/dist/utils/summaryGenerator.d.ts +2 -0
  82. package/dist/utils/summaryGenerator.js +183 -0
  83. package/dist/utils/uploadHandler.d.ts +31 -0
  84. package/dist/utils/uploadHandler.js +263 -0
  85. package/docs/AI_API.md +93 -0
  86. package/docs/CLAUDE.md +216 -0
  87. package/docs/PROJECT_SPECIFIC.md +1 -0
  88. package/docs/RECORD_COMMAND.md +262 -0
  89. package/docs/WORKFLOW_API.md +480 -0
  90. package/docs/bfy-splitting.md +126 -0
  91. package/docs/cli-commands.md +333 -0
  92. package/docs/examples/README.md +95 -0
  93. package/docs/examples/order-system.md +147 -0
  94. package/docs/examples/product-catalog.md +195 -0
  95. package/docs/examples/reports.md +187 -0
  96. package/docs/excel-export.md +216 -0
  97. package/docs/field-types/README.md +29 -0
  98. package/docs/field-types/calculated.md +147 -0
  99. package/docs/field-types/code-mappings.md +84 -0
  100. package/docs/field-types/custom.md +340 -0
  101. package/docs/object-specs/README.md +136 -0
  102. package/docs/object-specs/code-parameters.md +151 -0
  103. package/docs/object-specs/creating.md +203 -0
  104. package/docs/object-specs/js-code-examples.md +208 -0
  105. package/docs/object-specs/js-field-updates.md +168 -0
  106. package/docs/objects/README.md +89 -0
  107. package/docs/objects/creating.md +127 -0
  108. package/docs/page-layout.md +361 -0
  109. package/docs/permissions.md +260 -0
  110. package/docs/reports.md +197 -0
  111. package/docs/state-machines.md +544 -0
  112. package/docs/tasks/create-object.md +81 -0
  113. package/docs/translations.md +346 -0
  114. package/docs/twig-helpers.md +283 -0
  115. package/docs/webservices.md +159 -0
  116. package/docs/workspaces.md +176 -0
  117. package/package.json +59 -0
@@ -0,0 +1,346 @@
1
+ # Translations and Internationalization
2
+
3
+ Butterfly CMS includes a built-in translation system for managing multilingual content in the admin interface. This guide covers how translations work and how to manage them.
4
+
5
+ ## Overview
6
+
7
+ The translation system consists of three main tables:
8
+
9
+ | Table | Purpose |
10
+ |-------|---------|
11
+ | `bfy_languages` | Defines available languages (e.g., English, Turkish, German) |
12
+ | `bfy_translation_texts` | Stores source texts (original strings to be translated) |
13
+ | `bfy_translations` | Stores translated texts, linking languages to source texts |
14
+
15
+ ## Database Schema
16
+
17
+ ### bfy_languages
18
+
19
+ | Column | Type | Description |
20
+ |--------|------|-------------|
21
+ | `id` | int | Primary key |
22
+ | `name` | string | Language name (e.g., "English", "Turkish") |
23
+ | `iso_code` | string | ISO language code (e.g., "en", "tr") |
24
+ | `translations` | custom | Virtual field - renders the Translation Manager UI |
25
+
26
+ ### bfy_translation_texts
27
+
28
+ | Column | Type | Description |
29
+ |--------|------|-------------|
30
+ | `id` | int | Primary key |
31
+ | `source` | text | The original text to be translated |
32
+
33
+ ### bfy_translations
34
+
35
+ | Column | Type | Description |
36
+ |--------|------|-------------|
37
+ | `id` | int | Primary key |
38
+ | `bfy_language_id` | int | Reference to `bfy_languages` |
39
+ | `bfy_translation_text_id` | int | Reference to `bfy_translation_texts` |
40
+ | `text` | text | The translated text |
41
+
42
+ ## How It Works
43
+
44
+ 1. **Source texts** are stored in `bfy_translation_texts` - these are the original strings that need translation
45
+ 2. **Languages** are defined in `bfy_languages` - each language you want to support
46
+ 3. **Translations** link source texts to their translated versions in each language via `bfy_translations`
47
+
48
+ ### Translation Manager UI
49
+
50
+ When editing a language in `bfy_languages`, the `translations` custom field displays an interactive Translation Manager with:
51
+
52
+ - **Statistics**: Total strings, translated count, pending count
53
+ - **Search & Filter**: Search translations or filter by status (translated/untranslated)
54
+ - **Manual Entry**: Edit individual translations inline
55
+
56
+ ## CLI Translation Command
57
+
58
+ The `butterfly-cli translate` command provides efficient operations for managing translations without needing to read YAML files.
59
+
60
+ ### Operations
61
+
62
+ | Operation | Description |
63
+ |-----------|-------------|
64
+ | `languages` | List all languages with translation statistics |
65
+ | `get-untranslated` | Get untranslated texts for a language |
66
+ | `add` | Add or update a single translation |
67
+ | `bulk` | Bulk add/update translations from JSON file |
68
+
69
+ ### List Languages
70
+
71
+ ```bash
72
+ # List all languages with translation stats (table format)
73
+ butterfly-cli translate languages
74
+
75
+ # Output as JSON
76
+ butterfly-cli translate languages --format json
77
+ ```
78
+
79
+ **Example output:**
80
+ ```
81
+ ID | ISO | Name | Translated | Untranslated
82
+ ------------------------------------------------------------
83
+ 1 | en | English | 450/600 | 150
84
+ 2 | tr | Turkish | 580/600 | 20
85
+ 3 | de | German | 200/600 | 400
86
+ ```
87
+
88
+ ### Get Untranslated Texts
89
+
90
+ ```bash
91
+ # Get all untranslated texts for Turkish
92
+ butterfly-cli translate get-untranslated --lang tr
93
+
94
+ # Get first 50 untranslated texts
95
+ butterfly-cli translate get-untranslated --lang tr --limit 50
96
+
97
+ # Get untranslated as JSON (for processing)
98
+ butterfly-cli translate get-untranslated --lang tr --format json
99
+
100
+ # Use language ID instead of ISO code
101
+ butterfly-cli translate get-untranslated --lang-id 2
102
+ ```
103
+
104
+ ### Add Single Translation
105
+
106
+ ```bash
107
+ # Add translation by source text
108
+ butterfly-cli translate add --lang tr --source "Welcome" --text "Hoş geldiniz"
109
+
110
+ # Add translation by source ID
111
+ butterfly-cli translate add --lang tr --source-id 123 --text "Hoş geldiniz"
112
+
113
+ # Using language ID
114
+ butterfly-cli translate add --lang-id 2 --source "Save" --text "Kaydet"
115
+ ```
116
+
117
+ **Note:** The `add` command automatically detects if a translation exists and updates it instead of creating a duplicate.
118
+
119
+ ### Bulk Translation
120
+
121
+ Create a CSV file with tab-delimited columns (source and text):
122
+
123
+ ```
124
+ source text
125
+ Welcome Hoş geldiniz
126
+ Save Kaydet
127
+ Cancel İptal
128
+ Delete Sil
129
+ Hello, World! Merhaba, Dünya!
130
+ ```
131
+
132
+ > **Note:** Use TAB character as delimiter (not comma) to handle text containing commas. The header row is optional.
133
+
134
+ Then run:
135
+
136
+ ```bash
137
+ # Bulk translate from file
138
+ butterfly-cli translate bulk --lang tr --file translations.csv
139
+
140
+ # Using language ID
141
+ butterfly-cli translate bulk --lang-id 2 --file translations.csv
142
+ ```
143
+
144
+ **Bulk command behavior:**
145
+ - Creates missing source texts automatically
146
+ - Updates existing translations
147
+ - Creates new translations for untranslated texts
148
+ - Handles quoted fields with embedded tabs or newlines
149
+ - Reports summary with counts of added/updated/skipped/errors
150
+
151
+ ### Options Reference
152
+
153
+ | Option | Description |
154
+ |--------|-------------|
155
+ | `--lang <iso_code>` | Language ISO code (e.g., `tr`, `de`, `en`) |
156
+ | `--lang-id <id>` | Language ID (alternative to `--lang`) |
157
+ | `--source <text>` | Source text to translate |
158
+ | `--source-id <id>` | Source text ID (alternative to `--source`) |
159
+ | `--text <translation>` | Translated text (for `add` operation) |
160
+ | `-f, --file <path>` | CSV file path (tab-delimited) for `bulk` operation |
161
+ | `--format <format>` | Output format: `json` or `table` (default: `table`) |
162
+ | `--limit <count>` | Limit number of results |
163
+
164
+ ## Claude Code Translation Workflow (Recommended)
165
+
166
+ > **AI INSTRUCTION:** Use the `butterfly-cli translate` command for efficient translation operations. This eliminates the need to read YAML files and handles all edge cases automatically.
167
+
168
+ ### Step 1: List Languages and Check Status
169
+
170
+ ```bash
171
+ butterfly-cli translate languages
172
+ ```
173
+
174
+ ### Step 2: Get Untranslated Texts
175
+
176
+ ```bash
177
+ # Get untranslated texts as JSON for a language
178
+ butterfly-cli translate get-untranslated --lang tr --format json --limit 100
179
+ ```
180
+
181
+ ### Step 3: Add Translations
182
+
183
+ **For single translations:**
184
+ ```bash
185
+ butterfly-cli translate add --lang tr --source "Welcome" --text "Hoş geldiniz"
186
+ ```
187
+
188
+ **For bulk translations:** Create a tab-delimited CSV file and use:
189
+ ```bash
190
+ butterfly-cli translate bulk --lang tr --file translations.csv
191
+ ```
192
+
193
+ ### Complete Example Workflow
194
+
195
+ ```bash
196
+ # 1. Check which languages need translations
197
+ butterfly-cli translate languages
198
+
199
+ # 2. Get untranslated texts for Turkish (first 20)
200
+ butterfly-cli translate get-untranslated --lang tr --limit 20 --format json > untranslated.json
201
+
202
+ # 3. After translating, create translations.csv (tab-delimited):
203
+ # source text
204
+ # Original Translated
205
+
206
+ # 4. Bulk import translations
207
+ butterfly-cli translate bulk --lang tr --file translations.csv
208
+ ```
209
+
210
+ ## Managing Translations (Alternative Methods)
211
+
212
+ ### Adding a New Language
213
+
214
+ ```bash
215
+ butterfly-cli record add bfy_languages --data '{
216
+ "name": "German",
217
+ "iso_code": "de"
218
+ }'
219
+ ```
220
+
221
+ ### Adding Source Texts Manually
222
+
223
+ Source texts are typically added automatically by the system. To add manually:
224
+
225
+ ```bash
226
+ butterfly-cli record add bfy_translation_texts --data '{
227
+ "source": "Welcome to the application"
228
+ }'
229
+ ```
230
+
231
+ ### Using Record Command (Low-Level)
232
+
233
+ For direct database operations when needed:
234
+
235
+ ```bash
236
+ # Add a translation
237
+ butterfly-cli record add bfy_translations --data '{
238
+ "bfy_language_id": 2,
239
+ "bfy_translation_text_id": 1,
240
+ "text": "Willkommen bei der Anwendung"
241
+ }'
242
+
243
+ # Update an existing translation
244
+ butterfly-cli record edit bfy_translations --id 123 --data '{
245
+ "text": "Updated translation text"
246
+ }'
247
+ ```
248
+
249
+ ## Using Translations in Twig
250
+
251
+ ### Fetching Translations for a Language
252
+
253
+ ```twig
254
+ {# Get all translations for a specific language as key-value pairs #}
255
+ {% set translations = db()
256
+ .from('bfy_translations')
257
+ .where('bfy_language_id', languageId)
258
+ .keyToValue('bfy_translation_text_id', 'text')
259
+ %}
260
+
261
+ {# Access: translations[textId] returns the translated text #}
262
+ ```
263
+
264
+ ### Fetching Source Texts
265
+
266
+ ```twig
267
+ {% set sourceTexts = db()
268
+ .from('bfy_translation_texts')
269
+ .get()
270
+ %}
271
+ ```
272
+
273
+ ### Finding Untranslated Texts
274
+
275
+ ```twig
276
+ {% set texts = db().from('bfy_translation_texts').get() %}
277
+ {% set translations = db()
278
+ .from('bfy_translations')
279
+ .where('bfy_language_id', languageId)
280
+ .keyToValue('bfy_translation_text_id', 'text')
281
+ %}
282
+
283
+ {% set untranslated = [] %}
284
+ {% for text in texts %}
285
+ {% if not translations[text.id] %}
286
+ {% set untranslated = untranslated|merge([text]) %}
287
+ {% endif %}
288
+ {% endfor %}
289
+ ```
290
+
291
+ ## Related Tables
292
+
293
+ ### language_settings
294
+
295
+ A separate table for frontend/site language configuration:
296
+
297
+ | Column | Type | Description |
298
+ |--------|------|-------------|
299
+ | `lang_key` | string | Language key (e.g., "en", "tr") |
300
+ | `name` | string | Display name |
301
+ | `image` | string | Flag/icon image |
302
+
303
+ > **Note:** `language_settings` is for site/frontend language selection, while `bfy_languages` is for admin interface translations.
304
+
305
+ ## Download/Upload (YAML Files)
306
+
307
+ For working with YAML translation files, use the standard `download` and `upload` commands.
308
+
309
+ ### Download Translations
310
+
311
+ ```bash
312
+ # Download all resources (includes translations)
313
+ butterfly-cli download
314
+
315
+ # Download only translations
316
+ butterfly-cli download -t translations
317
+ ```
318
+
319
+ This creates YAML files in `butterfly-resources/translations/` (one file per language).
320
+
321
+ ### Upload Translations
322
+
323
+ ```bash
324
+ # Upload a specific language file
325
+ butterfly-cli upload ./butterfly-resources/translations/tr.yaml
326
+
327
+ # Upload all translation files
328
+ butterfly-cli upload ./butterfly-resources/translations/
329
+ ```
330
+
331
+ ### YAML File Format
332
+
333
+ ```yaml
334
+ "Welcome": "Hoş geldiniz"
335
+ "Save": "Kaydet"
336
+ "Cancel": "İptal"
337
+ "Delete": "" # Empty = not yet translated
338
+ ```
339
+
340
+ ## Best Practices
341
+
342
+ 1. **Use `translate` command**: Prefer `butterfly-cli translate` over reading YAML files for AI workflows
343
+ 2. **Bulk operations**: Use `translate bulk` for multiple translations in one operation
344
+ 3. **Check status first**: Always run `translate languages` to see translation progress
345
+ 4. **ISO codes**: Use standard ISO 639-1 codes (e.g., `tr`, `de`, `en`)
346
+ 5. **Auto-upsert**: The `translate add` command automatically updates existing translations
@@ -0,0 +1,283 @@
1
+ # Twig Helper Functions Reference
2
+
3
+ Reference for database queries, CRUD operations, and helper functions available in Butterfly Twig code.
4
+
5
+ ## Database Queries (db)
6
+
7
+ ### Basic Query
8
+
9
+ ```twig
10
+ {% set records = db()
11
+ .table('table_name')
12
+ .get()
13
+ %}
14
+ ```
15
+
16
+ ### With Different Database
17
+
18
+ ```twig
19
+ {% set records = db('database_alias')
20
+ .table('table_name')
21
+ .get()
22
+ %}
23
+ ```
24
+
25
+ ### Without Authentication (for webservices)
26
+
27
+ ```twig
28
+ {% set records = db('default', false)
29
+ .table('table_name')
30
+ .get()
31
+ %}
32
+ ```
33
+
34
+ ## Query Methods
35
+
36
+ ### Select Specific Columns
37
+
38
+ ```twig
39
+ {% set records = db()
40
+ .table('users')
41
+ .select('id', 'name', 'email')
42
+ .get()
43
+ %}
44
+ ```
45
+
46
+ ### Where Conditions
47
+
48
+ ```twig
49
+ {# Basic where #}
50
+ .where('status', 'active')
51
+
52
+ {# With operator #}
53
+ .where('price', '>', 100)
54
+
55
+ {# Multiple conditions #}
56
+ .where('status', 'active')
57
+ .where('category_id', 5)
58
+
59
+ {# Or where #}
60
+ .orWhere('status', 'pending')
61
+
62
+ {# Where in array #}
63
+ .whereIn('id', [1, 2, 3])
64
+
65
+ {# Where null #}
66
+ .whereNull('deleted_at')
67
+
68
+ {# Where not null #}
69
+ .whereNotNull('email')
70
+ ```
71
+
72
+ ### Joins
73
+
74
+ ```twig
75
+ {% set records = db()
76
+ .table('orders')
77
+ .join('users', 'users.id', '=', 'orders.user_id')
78
+ .select('orders.*', 'users.name as user_name')
79
+ .get()
80
+ %}
81
+
82
+ {# Left join #}
83
+ .leftJoin('categories', 'categories.id', '=', 'products.category_id')
84
+ ```
85
+
86
+ ### Ordering
87
+
88
+ ```twig
89
+ {# Ascending #}
90
+ .orderBy('created_at')
91
+
92
+ {# Descending #}
93
+ .orderByDesc('created_at')
94
+ ```
95
+
96
+ > **Note:** Use `orderByDesc('column')` instead of `orderBy('column', 'DESC')`.
97
+
98
+ ### Limiting
99
+
100
+ ```twig
101
+ .limit(10)
102
+ .offset(20)
103
+ ```
104
+
105
+ ### Grouping
106
+
107
+ ```twig
108
+ .groupBy('category_id')
109
+ ```
110
+
111
+ ## Result Methods
112
+
113
+ | Method | Returns | Description |
114
+ |--------|---------|-------------|
115
+ | `.get()` | array | All matching records |
116
+ | `.first()` | object/null | First matching record |
117
+ | `.count()` | integer | Count of matching records |
118
+ | `.sum('column')` | number | Sum of column values |
119
+ | `.avg('column')` | number | Average of column values |
120
+ | `.max('column')` | mixed | Maximum value |
121
+ | `.min('column')` | mixed | Minimum value |
122
+
123
+ ### Examples
124
+
125
+ ```twig
126
+ {% set users = db().table('users').where('is_active', 1).get() %}
127
+ {% set user = db().table('users').where('id', 5).first() %}
128
+ {% set total = db().table('orders').where('user_id', 5).count() %}
129
+ {% set sum = db().table('order_items').sum('total') %}
130
+ ```
131
+
132
+ ## Data Extraction Methods
133
+
134
+ | Method | Description | Example |
135
+ |--------|-------------|---------|
136
+ | `column('col')` | Array of single column values | `[1, 2, 3]` |
137
+ | `keyToValue('key', 'val')` | Map key to value | `{1: "John", 2: "Jane"}` |
138
+ | `keyToValue('key')` | Map key to full row | `{1: {id: 1, name: "John"}}` |
139
+ | `keyToValues('key', 'val')` | Map key to array of values | `{1: [100, 200], 2: [150]}` |
140
+ | `keyToValues('key')` | Map key to array of rows | `{1: [{...}, {...}]}` |
141
+
142
+ ### Examples
143
+
144
+ ```twig
145
+ {# Get array of IDs #}
146
+ {% set ids = db().table('users').column('id') %}
147
+ {# Result: [1, 2, 3] #}
148
+
149
+ {# Get id => name mapping #}
150
+ {% set userNames = db().table('users').keyToValue('id', 'name') %}
151
+ {# Result: {1: "John", 2: "Jane"} #}
152
+
153
+ {# Get id => full record mapping #}
154
+ {% set usersById = db().table('users').keyToValue('id') %}
155
+ {# Result: {1: {id: 1, name: "John", ...}} #}
156
+
157
+ {# Get user_id => order totals (multiple per user) #}
158
+ {% set ordersByUser = db().table('orders').keyToValues('user_id', 'total') %}
159
+ {# Result: {1: [100, 200], 2: [150]} #}
160
+ ```
161
+
162
+ > **Note:** There is no `pluck()` method. Use `column()` instead.
163
+
164
+ ## CRUD Operations
165
+
166
+ ### Insert
167
+
168
+ ```twig
169
+ {% set response = crud()
170
+ .table('users')
171
+ .insert({
172
+ "name": "John",
173
+ "email": "john@example.com"
174
+ })
175
+ %}
176
+
177
+ {% if response.success %}
178
+ New ID: {{ response.id }}
179
+ {% else %}
180
+ Error: {{ response.message }}
181
+ {% endif %}
182
+ ```
183
+
184
+ ### Update
185
+
186
+ ```twig
187
+ {% set response = crud()
188
+ .table('users')
189
+ .update({
190
+ "id": 5,
191
+ "name": "John Updated"
192
+ })
193
+ %}
194
+ ```
195
+
196
+ ### Delete
197
+
198
+ ```twig
199
+ {% set response = crud()
200
+ .table('users')
201
+ .delete({
202
+ "id": 5
203
+ })
204
+ %}
205
+ ```
206
+
207
+ ### Without Authentication (for webservices)
208
+
209
+ ```twig
210
+ {% set response = crud('default', false)
211
+ .table('submissions')
212
+ .insert({...})
213
+ %}
214
+ ```
215
+
216
+ ## Object Spec Helper Functions
217
+
218
+ Functions available in `processing_code` and `template_code`:
219
+
220
+ | Function | Context | Description |
221
+ |----------|---------|-------------|
222
+ | `getValue('column')` | processing_code | Get current record field value |
223
+ | `setValue('column', value)` | processing_code | Set field value |
224
+ | `errorMessage('msg')` | processing_code | Show error and stop processing |
225
+ | `getParameter('name')` | both | Get POST/GET parameter |
226
+ | `currentUser('field')` | both | Get current user info |
227
+ | `info.column` | template_code | Access current record data |
228
+
229
+ ### Examples
230
+
231
+ ```twig
232
+ {# In processing_code #}
233
+ {% set status = getValue('status') %}
234
+ {{ setValue('updated_at', 'now'|date('Y-m-d H:i:s')) }}
235
+ {{ errorMessage('Validation failed') }}
236
+
237
+ {# Get request parameter #}
238
+ {% set action = getParameter('action') %}
239
+
240
+ {# Get current user #}
241
+ {% set userId = currentUser('id') %}
242
+ {% set userEmail = currentUser('email') %}
243
+
244
+ {# In template_code #}
245
+ {{ info.title }}
246
+ {{ info.status }}
247
+ ```
248
+
249
+ ## Settings
250
+
251
+ Retrieve application settings stored in `cms_setting_groups` and `cms_settings` tables.
252
+
253
+ ```twig
254
+ {# Get a single setting value #}
255
+ {% set apiKey = setting('payment', 'api_key') %}
256
+
257
+ {# Get all settings in a group (returns object with alias => row mapping) #}
258
+ {% set paymentSettings = setting('payment') %}
259
+ {{ paymentSettings.api_key.value }}
260
+ {{ paymentSettings.secret_key.value }}
261
+ ```
262
+
263
+ | Parameter | Description |
264
+ |-----------|-------------|
265
+ | `group` | The `alias` from `cms_setting_groups` |
266
+ | `setting` | (Optional) The `alias` from `cms_settings` |
267
+
268
+ **Returns:** When `setting` is provided, returns the `value` field. When omitted, returns all settings in the group as `{alias: {value, val_1, val_2, ...}}`.
269
+
270
+ ## Important Notes
271
+
272
+ 1. **Integer indexes don't work in Twig arrays.** Use string prefixes:
273
+ ```twig
274
+ {# Wrong #}
275
+ {% set data = {0: 'a', 1: 'b'} %}
276
+
277
+ {# Correct #}
278
+ {% set data = {'item_0': 'a', 'item_1': 'b'} %}
279
+ ```
280
+
281
+ 2. **Cannot query multiple databases in single query.** Use separate queries.
282
+
283
+ 3. **Error checking:** Always check `.butterfly/error_log.txt` for Twig errors.