Skip to content

Commit 0cf9c96

Browse files
authored
implement import options, resolves #466 (#515)
1 parent 5f7c67b commit 0cf9c96

File tree

9 files changed

+158
-66
lines changed

9 files changed

+158
-66
lines changed

UPGRADE.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- **[IMPROVEMENT]** New field added to `form_builder_form_attributes`: `autocomplete`
55
- **[BUGFIX]** Solidify check for empty value in output transformer [#486](https://github.com/dachcom-digital/pimcore-formbuilder/issues/508)
66
- **[SECURITY FEATURE]** Math CAPTCHA Field [#511](https://github.com/dachcom-digital/pimcore-formbuilder/issues/511), read more about it [here](./docs/03_SpamProtection.md#math-captcha)
7+
- **[NEW FEATURE]** Form Import Options [#466](https://github.com/dachcom-digital/pimcore-formbuilder/issues/466)
78

89
## 5.2.0
910
- **[LICENSE]** Dual-License with GPL and Dachcom Commercial License (DCL) added

config/pimcore/routing.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,20 @@ form_builder.controller.admin.load_form_mail_editor_data:
2828
form_builder.controller.admin.export_form:
2929
path: /admin/formbuilder/settings/export-form/{id}
3030
defaults: { _controller: FormBuilderBundle\Controller\Admin\ExportController::exportFormAction }
31+
options:
32+
expose: true
33+
3134
form_builder.controller.admin.import_form:
3235
path: /admin/formbuilder/settings/import-form/{id}
3336
defaults: { _controller: FormBuilderBundle\Controller\Admin\ExportController::importFormAction }
37+
options:
38+
expose: true
3439

3540
form_builder.controller.admin.csv_export.export:
3641
path: /admin/formbuilder/export/mail-csv-export/{id}
3742
defaults: { _controller: FormBuilderBundle\Controller\Admin\ExportController::exportFormEmailsAction }
43+
options:
44+
expose: true
3845

3946
form_builder.controller.admin.get_group_templates:
4047
path: /admin/formbuilder/settings/get-group-templates

public/js/extjs/_form/tab/configPanel.js

+8-21
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ Formbuilder.extjs.formPanel.config = Class.create({
942942
return toolbar;
943943
},
944944

945-
showFormDoubleOptInData: function() {
945+
showFormDoubleOptInData: function () {
946946
new Formbuilder.extjs.extensions.formDoubleOptInData(this.formId, this.formConfig.doubleOptIn);
947947
},
948948

@@ -1180,42 +1180,27 @@ Formbuilder.extjs.formPanel.config = Class.create({
11801180
}
11811181
},
11821182

1183-
/**
1184-
* Create Import Panel (Upload File)
1185-
*/
11861183
showImportPanel: function () {
1187-
Ext.Msg.confirm(t('export'), t('form_builder.import_note'), function (btn) {
11881184

1189-
if (btn !== 'yes') {
1190-
return;
1191-
}
1185+
var importPanel;
11921186

1193-
var importPanel = new Formbuilder.extjs.components.formImporter(this);
1194-
importPanel.showPanel();
1195-
}.bind(this));
1187+
importPanel = new Formbuilder.extjs.components.formImporter(this);
1188+
importPanel.showPanel();
11961189
},
11971190

11981191
importForm: function (formId) {
11991192
this.formSelectionPanel.rebuildFormPanel(formId);
12001193
},
12011194

1202-
/**
1203-
* Trigger browser download (if form is valid)
1204-
* -> for form export
1205-
*/
12061195
exportForm: function () {
12071196

12081197
if (!this.formIsValid()) {
12091198
return;
12101199
}
12111200

1212-
pimcore.helpers.download('/admin/formbuilder/settings/export-form/' + this.formId);
1201+
pimcore.helpers.download(Routing.generate('form_builder.controller.admin.export_form', {id: this.formId}));
12131202
},
12141203

1215-
/**
1216-
* Trigger browser download
1217-
* -> for csv export of sent emails
1218-
*/
12191204
exportFormEmailCsv: function () {
12201205
var mailTypeField = this.exportPanel.query('combo'),
12211206
mailTypeValue = 'all';
@@ -1224,7 +1209,9 @@ Formbuilder.extjs.formPanel.config = Class.create({
12241209
mailTypeValue = mailTypeField[0].getValue();
12251210
}
12261211

1227-
pimcore.helpers.download('/admin/formbuilder/export/mail-csv-export/' + this.formId + '?mailType=' + mailTypeValue);
1212+
pimcore.helpers.download(
1213+
Routing.generate('form_builder.controller.admin.csv_export.export', {id: this.formId, mailType: mailTypeValue})
1214+
);
12281215
},
12291216

12301217
save: function (ev) {

public/js/extjs/components/formImporterComponent.js

+81-23
Original file line numberDiff line numberDiff line change
@@ -13,69 +13,127 @@ Formbuilder.extjs.components.formImporter = Class.create({
1313

1414
showPanel: function () {
1515

16-
var url = '/admin/formbuilder/settings/import-form/' + this.importId,
17-
uploadForm, requestParams = {};
16+
var uploadForm,
17+
requestParams = {};
1818

1919
this.uploadWindow = new Ext.Window({
2020
autoHeight: true,
2121
title: t('upload'),
2222
closeAction: 'close',
23-
width: 400,
23+
width: 600,
2424
modal: true
2525
});
2626

2727
if (pimcore.hasOwnProperty('settings') && pimcore.settings.hasOwnProperty('csrfToken')) {
28-
requestParams = {csrfToken: pimcore.settings['csrfToken'], formId: this.parentPanel.formId};
28+
requestParams = {
29+
csrfToken: pimcore.settings['csrfToken'],
30+
formId: this.parentPanel.formId
31+
};
2932
}
3033

3134
uploadForm = new Ext.form.FormPanel({
3235
bodyStyle: 'padding:10px',
3336
border: false,
3437
fileUpload: true,
35-
width: 400,
36-
items: [{
37-
xtype: 'fileuploadfield',
38-
emptyText: t('form_builder_upload_configuration_file'),
39-
fieldLabel: t('form_builder_file'),
40-
width: 300,
41-
name: 'formData',
42-
buttonText: '',
43-
buttonConfig: {
44-
iconCls: 'pimcore_icon_upload'
38+
autoHeight: true,
39+
items: [
40+
{
41+
xtype: 'fieldset',
42+
title: t('form_builder_upload_configuration.section'),
43+
collapsible: false,
44+
collapsed: false,
45+
autoHeight: true,
46+
defaults: {
47+
labelWidth: 170
48+
},
49+
name: 'options',
50+
items: [
51+
{
52+
xtype: 'label',
53+
style: 'display:block; padding:5px; background:#fff; border:1px solid #eee; font-weight: 300;',
54+
text: t('form_builder.import_note')
55+
},
56+
{
57+
xtype: 'checkbox',
58+
value: true,
59+
inputValue: true,
60+
uncheckedValue: false,
61+
fieldLabel: t('form_builder_upload_configuration.section.output_workflows'),
62+
name: 'outputWorkflows',
63+
},
64+
{
65+
xtype: 'checkbox',
66+
value: true,
67+
inputValue: true,
68+
uncheckedValue: false,
69+
fieldLabel: t('form_builder_upload_configuration.section.conditional_logic'),
70+
name: 'conditionalLogic',
71+
}
72+
]
73+
},
74+
{
75+
xtype: 'fileuploadfield',
76+
emptyText: t('form_builder_upload_configuration.file'),
77+
fieldLabel: t('form_builder_file'),
78+
name: 'formData',
79+
allowBlank: false,
80+
width: '100%',
81+
buttonConfig: {
82+
iconCls: 'pimcore_icon_upload'
83+
}
4584
},
46-
listeners: {
47-
change: function () {
85+
{
86+
xtype: 'button',
87+
text: t('import'),
88+
iconCls: 'pimcore_icon_import',
89+
handler: function (b) {
90+
91+
if (!uploadForm.isValid()) {
92+
return;
93+
}
94+
95+
b.setDisabled(true);
96+
4897
uploadForm.getForm().submit({
49-
url: url,
50-
params: requestParams,
98+
url: Routing.generate('form_builder.controller.admin.import_form', {id: this.importId}),
99+
params: Ext.Object.merge(requestParams, uploadForm.getValues()),
51100
waitMsg: t('please_wait'),
52101
success: this.getImportComplete.bind(this),
53102
failure: function (el, data) {
103+
104+
var response;
105+
54106
this.uploadWindow.close();
55-
var response = Ext.decode(data.response.responseText);
56-
Ext.Msg.alert(t('error'), response && response.hasOwnProperty('message') ? response.message : data.response.responseText);
107+
response = Ext.decode(data.response.responseText);
108+
109+
Ext.Msg.alert(
110+
t('error'),
111+
response && response.hasOwnProperty('message')
112+
? response.message
113+
: data.response.responseText
114+
);
57115
}.bind(this)
58116
});
59117
}.bind(this)
60118
}
61-
}]
119+
]
62120
});
63121

64122
this.uploadWindow.add(uploadForm);
65123
this.uploadWindow.show();
66124
this.uploadWindow.setWidth(400);
67125
this.uploadWindow.updateLayout();
68-
69126
},
70127

71128
getImportComplete: function (el, data) {
129+
72130
var response = Ext.decode(data.response.responseText);
73131
this.uploadWindow.close();
132+
74133
if (response.success === true) {
75134
this.parentPanel.importForm(response.formId);
76135
} else {
77136
Ext.Msg.alert(t('error'), response.message);
78137
}
79138
}
80-
81139
});

src/Controller/Admin/ExportController.php

+28-4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function __construct(protected FormDefinitionManager $formDefinitionManag
4040
public function importFormAction(Request $request, ImportExportProcessor $importExportProcessor): JsonResponse
4141
{
4242
$formId = (int) $request->request->get('formId');
43+
4344
/** @var UploadedFile $file */
4445
$file = $request->files->get('formData');
4546
$data = file_get_contents($file->getPathname());
@@ -55,14 +56,24 @@ public function importFormAction(Request $request, ImportExportProcessor $import
5556
'message' => null,
5657
];
5758

59+
$importOptions = [
60+
ImportExportProcessor::FORM_SECTION_OUTPUT_WORKFLOWS => $request->request->get('outputWorkflows') === 'true',
61+
ImportExportProcessor::FORM_SECTION_CONDITIONAL_LOGIC => $request->request->get('conditionalLogic') === 'true',
62+
];
63+
5864
try {
59-
$importExportProcessor->processYamlToFormDefinition($formId, $data);
65+
$importExportProcessor->processYamlToFormDefinition($formId, $data, $importOptions);
6066
} catch (\Throwable $e) {
6167
$response['success'] = false;
6268
$response['message'] = sprintf('Error while importing form definition: %s', $e->getMessage());
6369
}
6470

65-
return new JsonResponse(json_encode($response, JSON_THROW_ON_ERROR), 200, ['Content-Type' => 'text/plain'], true);
71+
return new JsonResponse(
72+
json_encode($response, JSON_THROW_ON_ERROR),
73+
200,
74+
['Content-Type' => 'text/plain'],
75+
true
76+
);
6677
}
6778

6879
public function exportFormAction(Request $request, ImportExportProcessor $importExportProcessor): Response
@@ -102,10 +113,23 @@ public function exportFormEmailsAction(Request $request): Response
102113
}
103114

104115
$emailLogs = new Email\Log\Listing();
105-
$emailLogs->addConditionParam('params LIKE :form', ['form' => sprintf('%%%s%%', $this->generateFormIdQuery($formId))]);
116+
$emailLogs->addConditionParam(
117+
'params LIKE :form',
118+
[
119+
'form' => sprintf('%%%s%%', $this->generateFormIdQuery($formId))
120+
]
121+
);
106122

107123
if ($filter !== 'all') {
108-
$emailLogs->addConditionParam('params LIKE :workflow', ['workflow' => sprintf('%%%s%%', $this->generateOutputWorkflowFilterQuery($formId, (int) $filter))]);
124+
$emailLogs->addConditionParam(
125+
'params LIKE :workflow',
126+
[
127+
'workflow' => sprintf(
128+
'%%%s%%',
129+
$this->generateOutputWorkflowFilterQuery($formId, (int) $filter)
130+
)
131+
]
132+
);
109133
}
110134

111135
$response = new Response();

src/Tool/ImportExportProcessor.php

+20-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
class ImportExportProcessor
2626
{
27+
public const FORM_SECTION_OUTPUT_WORKFLOWS = 'outputWorkflows';
28+
public const FORM_SECTION_CONDITIONAL_LOGIC = 'conditionalLogic';
29+
2730
public function __construct(
2831
protected Connection $connection,
2932
protected FormDefinitionManager $formDefinitionManager,
@@ -36,7 +39,6 @@ public function __construct(
3639
*/
3740
public function processFormDefinitionToYaml(int $formId): string
3841
{
39-
// load raw entity
4042
$fQb = $this->connection->createQueryBuilder();
4143
$fQb
4244
->select('*')
@@ -58,7 +60,7 @@ public function processFormDefinitionToYaml(int $formId): string
5860
->setParameter('id', $formId);
5961

6062
$outputWorkflows = [];
61-
foreach ($fowQb->execute()->fetchAllAssociative() as $rawFormOutputWorkflowDefinition) {
63+
foreach ($fowQb->executeQuery()->fetchAllAssociative() as $rawFormOutputWorkflowDefinition) {
6264
$fowChannelQb = $this->connection->createQueryBuilder();
6365
$fowChannelQb
6466
->select('*')
@@ -67,11 +69,11 @@ public function processFormDefinitionToYaml(int $formId): string
6769
->setParameter('id', $rawFormOutputWorkflowDefinition['id']);
6870

6971
$channels = [];
70-
foreach ($fowChannelQb->execute()->fetchAllAssociative() as $rawFormOutputWorkflowChannelDefinition) {
72+
foreach ($fowChannelQb->executeQuery()->fetchAllAssociative() as $rawFormOutputWorkflowChannelDefinition) {
7173
$channels[] = [
72-
'type' => $rawFormOutputWorkflowChannelDefinition['type'],
73-
'name' => $rawFormOutputWorkflowChannelDefinition['name'],
74-
'configuration' => is_string($rawFormOutputWorkflowChannelDefinition['configuration'])
74+
'type' => $rawFormOutputWorkflowChannelDefinition['type'],
75+
'name' => $rawFormOutputWorkflowChannelDefinition['name'],
76+
'configuration' => is_string($rawFormOutputWorkflowChannelDefinition['configuration'])
7577
? unserialize($rawFormOutputWorkflowChannelDefinition['configuration'], ['allowed_classes' => false])
7678
: null,
7779
'funnel_actions' => is_string($rawFormOutputWorkflowChannelDefinition['funnel_actions'])
@@ -109,7 +111,7 @@ public function processFormDefinitionToYaml(int $formId): string
109111
/**
110112
* @throws \Throwable
111113
*/
112-
public function processYamlToFormDefinition(int $formId, mixed $data): void
114+
public function processYamlToFormDefinition(int $formId, mixed $data, array $importOptions): void
113115
{
114116
$formContent = Yaml::parse($data);
115117

@@ -124,14 +126,21 @@ public function processYamlToFormDefinition(int $formId, mixed $data): void
124126
}
125127

126128
$data = [
127-
'form_name' => $formDefinition->getName(),
128-
'form_config' => $formContent['configuration'] ?? [],
129-
'form_conditional_logic' => $formContent['conditional_logic'] ?? [],
130-
'form_fields' => $formContent['fields'] ? ['fields' => $formContent['fields']] : [],
129+
'form_name' => $formDefinition->getName(),
130+
'form_config' => $formContent['configuration'] ?? [],
131+
'form_fields' => $formContent['fields'] ? ['fields' => $formContent['fields']] : [],
131132
];
132133

134+
if ($importOptions[self::FORM_SECTION_CONDITIONAL_LOGIC] === true) {
135+
$data['form_conditional_logic'] = $formContent['conditional_logic'] ?? [];
136+
}
137+
133138
$this->formDefinitionManager->save($data, $formDefinition->getId());
134139

140+
if ($importOptions[self::FORM_SECTION_OUTPUT_WORKFLOWS] === false) {
141+
return;
142+
}
143+
135144
// remove all workflows and channels first (yes, we informed users about that earlier)
136145
/** @var OutputWorkflowInterface $outputWorkflow */
137146
foreach ($formDefinition->getOutputWorkflows() as $outputWorkflow) {

0 commit comments

Comments
 (0)