Skip to content

Commit cee292f

Browse files
authored
data injector, resolves #395 (#396)
1 parent dadfcc9 commit cee292f

File tree

22 files changed

+545
-49
lines changed

22 files changed

+545
-49
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
```json
2323
"require" : {
24-
"dachcom-digital/formbuilder" : "~4.4.0"
24+
"dachcom-digital/formbuilder" : "~4.5.0"
2525
}
2626
```
2727

@@ -74,6 +74,8 @@ Nothing to tell here, it's just [Symfony](https://symfony.com/doc/current/templa
7474
- [Custom Adapter](docs/DynamicMultiFile/99_CustomAdapter.md)
7575
- [Conditional Logic](docs/81_ConditionalLogic.md)
7676
- [Form & Field Attributes](docs/83_Attributes.md)
77+
- [Form Runtime Data](docs/85_RuntimeData.md))
78+
- [Form Data Injection](docs/86_FormDataInjection.md)
7779
- [Frontend Tips](docs/90_FrontendTips.md)
7880
- [FormBuilder Javascript Plugins](docs/91_Javascript.md)
7981
- [Configuration Flags](docs/100_ConfigurationFlags.md)

UPGRADE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- **[BUGFIX]**: suppress php warning of undefined array key [@jheimbach](https://github.com/dachcom-digital/pimcore-formbuilder/pull/387)
66
- **[ENHANCEMENT]**: Adds sort buttons for choices in ChoiceType [@jheimbach](https://github.com/dachcom-digital/pimcore-formbuilder/pull/388)
77
- **[ENHANCEMENT]**: Allow Relation(s) in Object Channel [#390](https://github.com/dachcom-digital/pimcore-formbuilder/issues/390)
8+
- **[NEW FEATURE]**: Data Injectors [#395](https://github.com/dachcom-digital/pimcore-formbuilder/issues/395)
89

910
## Version 4.4.1
1011
- **[BUGFIX]**: [Constraint Options] ignore internal properties [#381](https://github.com/dachcom-digital/pimcore-formbuilder/pull/381)

docs/30_FormTypes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,6 @@ parameters:
9090
- ['label','label']
9191
- ['p','p']
9292
```
93+
94+
## Data Injection
95+
If you want to add data to your text fields, based on a specific condition (a query parameter in request for example) you may want to check out [form data injectors](./86_FormDataInjection.md).

docs/86_FormDataInjection.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Form Data Injection
2+
![image](https://github.com/dachcom-digital/pimcore-formbuilder/assets/700119/b6375824-bfeb-4705-8de1-36f174ebb7eb)
3+
4+
Sometimes it's required to set specific data for a given form field.
5+
To do that, we usually fill up the `data` options field.
6+
7+
In case this data should be fluid, you need to hook into some form events which requires developers to do that.
8+
9+
To make things easier, we've introduced the Data Injection Section.
10+
There is also a preconfigured `expression` injector.
11+
12+
This feature is available for:
13+
- Hidden Type
14+
- Integer Type
15+
- Text Type
16+
- Textarea Type
17+
-
18+
19+
***
20+
21+
## Expression Data Injector
22+
![image](https://github.com/dachcom-digital/pimcore-formbuilder/assets/700119/53b9cde9-9057-4034-b1c3-895c5466c3ea)
23+
24+
Use this injector for the most common scenario: Link a request parameter to a given form.
25+
Within the expression injecor, you're allowed to fetch data from symfonys `request` object.
26+
27+
Example: `request.query.get('myEventId')` or `request.attributes.get('siteId')`
28+
29+
***
30+
31+
## Custom Data Injector
32+
33+
```yaml
34+
services:
35+
App\Form\DataInjector\MyDataInjector:
36+
tags:
37+
- { name: form_builder.data_injector, identifier: my_data_injector }
38+
```
39+
40+
```php
41+
<?php
42+
43+
namespace App\FormBuilder\Form\DataInjector;
44+
45+
class MyDataInjector implements DataInjectorInterface
46+
{
47+
public function getName(): string
48+
{
49+
return 'My Data Injector';
50+
}
51+
52+
public function getDescription(): ?string
53+
{
54+
return 'My Description';
55+
}
56+
57+
public function parseData(array $config): mixed
58+
{
59+
if (!array_key_exists('my_additional_config_node', $config)) {
60+
return null;
61+
}
62+
63+
$config = $config['my_additional_config_node'];
64+
65+
// do your logic
66+
$newData = null;
67+
68+
return $newData;
69+
}
70+
}
71+
```
72+
73+
```js
74+
pimcore.registerNS('Formbuilder.extjs.form.dataInjection.my_data_injector');
75+
Formbuilder.extjs.form.dataInjection.my_data_injector = Class.create({
76+
getForm: function (data) {
77+
return [{
78+
xtype: 'textfield',
79+
fieldLabel: 'Required Additional Config Node',
80+
name: 'my_additional_config_node',
81+
anchor: '100%',
82+
allowBlank: false,
83+
value: data !== null ? data.my_additional_config_node : null
84+
}];
85+
}
86+
});
87+
88+
```

src/FormBuilderBundle/Controller/Admin/SettingsController.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
use FormBuilderBundle\Builder\ExtJsFormBuilder;
66
use FormBuilderBundle\Configuration\Configuration;
7+
use FormBuilderBundle\Form\DataInjector\DataInjectorInterface;
78
use FormBuilderBundle\Manager\FormDefinitionManager;
89
use FormBuilderBundle\Manager\PresetManager;
910
use FormBuilderBundle\Registry\ChoiceBuilderRegistry;
1011
use FormBuilderBundle\Model\FormDefinitionInterface;
12+
use FormBuilderBundle\Registry\DataInjectionRegistry;
1113
use FormBuilderBundle\Tool\FormDependencyLocator;
1214
use Pimcore\Bundle\AdminBundle\Controller\AdminController;
1315
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -287,6 +289,26 @@ public function getPresetDescriptionAction(Request $request, PresetManager $pres
287289
);
288290
}
289291

292+
public function getDataInjectionStoreAction(Request $request, DataInjectionRegistry $dataInjectionRegistry): JsonResponse
293+
{
294+
$store = [];
295+
296+
foreach ($dataInjectionRegistry->getAll() as $dataInjectorIdentifier => $dataInjectorService) {
297+
$store[] = [
298+
'value' => $dataInjectorIdentifier,
299+
'label' => $dataInjectorService->getName(),
300+
'description' => $dataInjectorService->getDescription()
301+
];
302+
}
303+
304+
return $this->json(
305+
[
306+
'success' => true,
307+
'store' => $store
308+
]
309+
);
310+
}
311+
290312
private function getSaveName(string $name): string
291313
{
292314
return (string) preg_replace('/[^A-Za-z0-9aäüöÜÄÖß \-]/', '', $name);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace FormBuilderBundle\DependencyInjection\CompilerPass;
4+
5+
use FormBuilderBundle\Registry\DataInjectionRegistry;
6+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
7+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
8+
use Symfony\Component\DependencyInjection\ContainerBuilder;
9+
use Symfony\Component\DependencyInjection\Reference;
10+
11+
final class DataInjectionPass implements CompilerPassInterface
12+
{
13+
public function process(ContainerBuilder $container): void
14+
{
15+
$definition = $container->getDefinition(DataInjectionRegistry::class);
16+
foreach ($container->findTaggedServiceIds('form_builder.data_injector') as $id => $tags) {
17+
foreach ($tags as $attributes) {
18+
if (!isset($attributes['identifier'])) {
19+
throw new InvalidConfigurationException(sprintf('You need to define a valid identifier for data injector "%s"', $id));
20+
}
21+
22+
$definition->addMethodCall('register', [$attributes['identifier'], new Reference($id)]);
23+
}
24+
}
25+
}
26+
}

src/FormBuilderBundle/EventSubscriber/FormBuilderSubscriber.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace FormBuilderBundle\EventSubscriber;
44

5+
use FormBuilderBundle\Registry\DataInjectionRegistry;
56
use FormBuilderBundle\Validator\Constraints\DynamicMultiFileNotBlank;
67
use FormBuilderBundle\Model\FieldDefinitionInterface;
78
use FormBuilderBundle\Model\FormFieldContainerDefinitionInterface;
@@ -25,24 +26,16 @@
2526

2627
class FormBuilderSubscriber implements EventSubscriberInterface
2728
{
28-
protected Configuration $configuration;
29-
protected EventDispatcherInterface $eventDispatcher;
30-
protected Dispatcher $dispatcher;
31-
protected FormRegistryInterface $formRegistry;
32-
3329
private array $availableConstraints;
3430
private array $availableFormTypes;
3531

3632
public function __construct(
37-
Configuration $configuration,
38-
EventDispatcherInterface $eventDispatcher,
39-
Dispatcher $dispatcher,
40-
FormRegistryInterface $formRegistry
33+
protected Configuration $configuration,
34+
protected EventDispatcherInterface $eventDispatcher,
35+
protected Dispatcher $dispatcher,
36+
protected FormRegistryInterface $formRegistry,
37+
protected DataInjectionRegistry $dataInjectionRegistry
4138
) {
42-
$this->configuration = $configuration;
43-
$this->eventDispatcher = $eventDispatcher;
44-
$this->dispatcher = $dispatcher;
45-
$this->formRegistry = $formRegistry;
4639
$this->availableConstraints = $this->configuration->getAvailableConstraints();
4740
$this->availableFormTypes = $this->configuration->getConfig('types');
4841
}
@@ -204,15 +197,19 @@ private function addFormBuilderField(FormFieldDefinitionInterface $field, array
204197

205198
// options enrichment: tweak preferred choice options
206199
if (in_array($field->getType(), $this->getChoiceFieldTypes(), true)) {
207-
if (isset($options['multiple']) && $options['multiple'] === false
208-
&& isset($options['data'])
209-
&& is_array($options['data'])
210-
&& !empty($options['data'])
211-
) {
200+
if (isset($options['multiple']) && $options['multiple'] === false && array_key_exists('data', $options) && is_array($options['data'])) {
212201
$options['data'] = $options['data'][0];
213202
}
214203
}
215204

205+
if (array_key_exists('dataInjection', $options) && !empty($options['dataInjection'])) {
206+
$dataInjection = json_decode($options['dataInjection'], true);
207+
unset($options['dataInjection']);
208+
if ($this->dataInjectionRegistry->has($dataInjection['injector'])) {
209+
$options['data'] = $this->dataInjectionRegistry->get($dataInjection['injector'])->parseData($dataInjection['config']);
210+
}
211+
}
212+
216213
// options enrichment: add constraints
217214
if (in_array('constraints', $availableOptions)) {
218215
$conditionalConstraintData = $this->dispatchConditionalLogicModule('constraints', $conditionalLogicOptions);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace FormBuilderBundle\Form\DataInjector;
4+
5+
interface DataInjectorInterface
6+
{
7+
public function getName(): string;
8+
9+
public function getDescription(): ?string;
10+
11+
public function parseData(array $config): mixed;
12+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace FormBuilderBundle\Form\DataInjector;
4+
5+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
6+
use Symfony\Component\HttpFoundation\Request;
7+
use Symfony\Component\HttpFoundation\RequestStack;
8+
9+
class ExpressionDataInjector implements DataInjectorInterface
10+
{
11+
protected ExpressionLanguage $expressionLanguage;
12+
13+
public function __construct(protected RequestStack $requestStack)
14+
{
15+
$this->expressionLanguage = new ExpressionLanguage();
16+
}
17+
18+
public function getName(): string
19+
{
20+
return 'Expression';
21+
}
22+
23+
public function getDescription(): ?string
24+
{
25+
return 'Inject data from request object via expression language';
26+
}
27+
28+
public function parseData(array $config): mixed
29+
{
30+
if (!array_key_exists('expression', $config)) {
31+
return null;
32+
}
33+
34+
$request = $this->requestStack->getMainRequest();
35+
36+
if (!$request instanceof Request) {
37+
return null;
38+
}
39+
40+
return $this->expressionLanguage->evaluate($config['expression'], ['request' => $request]);
41+
}
42+
}

src/FormBuilderBundle/FormBuilderBundle.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Doctrine\DBAL\Types\Type;
77
use FormBuilderBundle\DependencyInjection\CompilerPass\ApiProviderPass;
88
use FormBuilderBundle\DependencyInjection\CompilerPass\ChoiceBuilderPass;
9+
use FormBuilderBundle\DependencyInjection\CompilerPass\DataInjectionPass;
910
use FormBuilderBundle\DependencyInjection\CompilerPass\DispatcherPass;
1011
use FormBuilderBundle\DependencyInjection\CompilerPass\DynamicMultiFileAdapterPass;
1112
use FormBuilderBundle\DependencyInjection\CompilerPass\DynamicObjectResolverPass;
@@ -69,6 +70,7 @@ public function build(ContainerBuilder $container): void
6970
$container->addCompilerPass(new ApiProviderPass());
7071
$container->addCompilerPass(new FieldTransformerPass());
7172
$container->addCompilerPass(new StorageProviderPass());
73+
$container->addCompilerPass(new DataInjectionPass());
7274
}
7375

7476
public function getInstaller(): Install
@@ -111,6 +113,7 @@ public function getJsPaths(): array
111113
'/bundles/formbuilder/js/extjs/_form/config-fields/select.js',
112114
'/bundles/formbuilder/js/extjs/_form/config-fields/tagfield.js',
113115
'/bundles/formbuilder/js/extjs/_form/config-fields/textfield.js',
116+
'/bundles/formbuilder/js/extjs/_form/data-injection/expression.js',
114117
'/bundles/formbuilder/js/extjs/extensions/formMetaData.js',
115118
'/bundles/formbuilder/js/extjs/extensions/formMailEditor.js',
116119
'/bundles/formbuilder/js/extjs/extensions/formApiMappingEditor.js',

0 commit comments

Comments
 (0)