Issues (3627)

Form/Type/EntityFieldsBuildFormTrait.php (1 issue)

1
<?php
2
3
/*
4
 * @copyright   2016 Mautic Contributors. All rights reserved
5
 * @author      Mautic
6
 *
7
 * @link        http://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace Mautic\LeadBundle\Form\Type;
13
14
use Mautic\CoreBundle\Form\Type\BooleanType;
15
use Mautic\CoreBundle\Form\Type\CountryType;
16
use Mautic\CoreBundle\Form\Type\LocaleType;
17
use Mautic\CoreBundle\Form\Type\LookupType;
18
use Mautic\CoreBundle\Form\Type\MultiselectType;
19
use Mautic\CoreBundle\Form\Type\RegionType;
20
use Mautic\CoreBundle\Form\Type\SelectType;
21
use Mautic\CoreBundle\Form\Type\TimezoneType;
22
use Mautic\CoreBundle\Helper\DateTimeHelper;
23
use Mautic\LeadBundle\Exception\FieldNotFoundException;
24
use Mautic\LeadBundle\Form\FieldAliasToFqcnMap;
25
use Mautic\LeadBundle\Helper\FormFieldHelper;
26
use Mautic\LeadBundle\Validator\Constraints\Length;
27
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
28
use Symfony\Component\Form\Extension\Core\Type\DateType;
29
use Symfony\Component\Form\Extension\Core\Type\EmailType;
30
use Symfony\Component\Form\Extension\Core\Type\NumberType;
31
use Symfony\Component\Form\Extension\Core\Type\TextType;
32
use Symfony\Component\Form\Extension\Core\Type\TimeType;
33
use Symfony\Component\Form\FormBuilderInterface;
34
use Symfony\Component\Form\FormEvent;
35
use Symfony\Component\Form\FormEvents;
36
use Symfony\Component\Validator\Constraints\Email;
37
use Symfony\Component\Validator\Constraints\NotBlank;
38
39
trait EntityFieldsBuildFormTrait
40
{
41
    private function getFormFields(FormBuilderInterface $builder, array $options, $object = 'lead')
42
    {
43
        $cleaningRules = [];
44
        $fieldValues   = [];
45
        $isObject      = false;
46
        if (!empty($options['data'])) {
47
            $isObject    = is_object($options['data']);
48
            $fieldValues = ($isObject) ? $options['data']->getFields() : $options['data'];
49
        }
50
        $mapped = !$isObject;
51
52
        foreach ($options['fields'] as $field) {
53
            if (false === $field['isPublished'] || $field['object'] !== $object) {
54
                continue;
55
            }
56
            $attr       = ['class' => 'form-control'];
57
            $properties = $field['properties'];
58
            $type       = $field['type'];
59
            $required   = ($isObject) ? $field['isRequired'] : false;
60
            $alias      = $field['alias'];
61
            $group      = $field['group'];
62
63
            try {
64
                $type = FieldAliasToFqcnMap::getFqcn($type);
65
            } catch (FieldNotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
66
            }
67
68
            if ($field['isUniqueIdentifer']) {
69
                $attr['data-unique-identifier'] = $field['alias'];
70
            }
71
72
            if ($isObject) {
73
                $value = (isset($fieldValues[$group][$alias]['value'])) ?
74
                    $fieldValues[$group][$alias]['value'] : $field['defaultValue'];
75
            } else {
76
                $value = (isset($fieldValues[$alias])) ? $fieldValues[$alias] : '';
77
            }
78
79
            $constraints = [];
80
            if ($required && empty($options['ignore_required_constraints'])) {
81
                $constraints[] = new NotBlank(
82
                    ['message' => 'mautic.lead.customfield.notblank']
83
                );
84
            } elseif (!empty($options['ignore_required_constraints'])) {
85
                $required            = false;
86
                $field['isRequired'] = false;
87
            }
88
89
            switch ($type) {
90
                case NumberType::class:
91
                    if (empty($properties['scale'])) {
92
                        $properties['scale'] = null;
93
                    } //ensure default locale is used
94
                    else {
95
                        $properties['scale'] = (int) $properties['scale'];
96
                    }
97
98
                    if ('' === $value) {
99
                        // Prevent transform errors
100
                        $value = null;
101
                    }
102
103
                    $builder->add(
104
                        $alias,
105
                        $type,
106
                        [
107
                            'required'      => $required,
108
                            'label'         => $field['label'],
109
                            'label_attr'    => ['class' => 'control-label'],
110
                            'attr'          => $attr,
111
                            'data'          => (null !== $value) ? (float) $value : $value,
112
                            'mapped'        => $mapped,
113
                            'constraints'   => $constraints,
114
                            'scale'         => $properties['scale'],
115
                            'rounding_mode' => isset($properties['roundmode']) ? (int) $properties['roundmode'] : 0,
116
                        ]
117
                    );
118
                    break;
119
                case DateType::class:
120
                case DateTimeType::class:
121
                case TimeType::class:
122
                    $opts                = [
123
                        'required'    => $required,
124
                        'label'       => $field['label'],
125
                        'label_attr'  => ['class' => 'control-label'],
126
                        'attr'        => $attr,
127
                        'mapped'      => $mapped,
128
                        'constraints' => $constraints,
129
                    ];
130
131
                if (!empty($options['ignore_date_type'])) {
132
                    $type = TextType::class;
133
                } else {
134
                    $opts['html5']  = false;
135
                    $opts['input']  = 'string';
136
                    $opts['widget'] = 'single_text';
137
                    if ($value) {
138
                        try {
139
                            $dtHelper = new DateTimeHelper($value, null, 'local');
140
                        } catch (\Exception $e) {
141
                            // Rather return empty value than break the page
142
                            $value = null;
143
                        }
144
                    }
145
                    if (DateTimeType::class === $type) {
146
                        $opts['attr']['data-toggle'] = 'datetime';
147
                        $opts['model_timezone']      = 'UTC';
148
                        $opts['view_timezone']       = date_default_timezone_get();
149
                        $opts['format']              = 'yyyy-MM-dd HH:mm:ss';
150
                        $opts['with_seconds']        = true;
151
152
                        $opts['data'] = (!empty($value)) ? $dtHelper->toLocalString('Y-m-d H:i:s') : null;
153
                    } elseif (DateType::class === $type) {
154
                        $opts['attr']['data-toggle'] = 'date';
155
                        $opts['data']                = (!empty($value)) ? $dtHelper->toLocalString('Y-m-d') : null;
156
                    } else {
157
                        $opts['attr']['data-toggle'] = 'time';
158
                        $opts['model_timezone']      = 'UTC';
159
                        // $opts['with_seconds']   = true; // @todo figure out why this cause the contact form to fail.
160
                        $opts['view_timezone'] = date_default_timezone_get();
161
                        $opts['data']          = (!empty($value)) ? $dtHelper->toLocalString('H:i:s') : null;
162
                    }
163
164
                    $builder->addEventListener(
165
                        FormEvents::PRE_SUBMIT,
166
                        function (FormEvent $event) use ($alias, $type) {
167
                            $data = $event->getData();
168
169
                            if (!empty($data[$alias])) {
170
                                if (false === ($timestamp = strtotime($data[$alias]))) {
171
                                    $timestamp = null;
172
                                }
173
                                if ($timestamp) {
174
                                    $dtHelper = new DateTimeHelper(date('Y-m-d H:i:s', $timestamp), null, 'local');
175
                                    switch ($type) {
176
                                        case DateTimeType::class:
177
                                            $data[$alias] = $dtHelper->toLocalString('Y-m-d H:i:s');
178
                                            break;
179
                                        case DateType::class:
180
                                            $data[$alias] = $dtHelper->toLocalString('Y-m-d');
181
                                            break;
182
                                        case TimeType::class:
183
                                            $data[$alias] = $dtHelper->toLocalString('H:i:s');
184
                                            break;
185
                                    }
186
                                }
187
                            }
188
                            $event->setData($data);
189
                        }
190
                    );
191
                }
192
193
                    $builder->add($alias, $type, $opts);
194
                    break;
195
                case SelectType::class:
196
                case MultiselectType::class:
197
                case BooleanType::class:
198
                    if (MultiselectType::class === $type) {
199
                        $constraints[] = new Length(['max' => 65535]);
200
                    }
201
202
                    $typeProperties = [
203
                        'required'    => $required,
204
                        'label'       => $field['label'],
205
                        'attr'        => $attr,
206
                        'mapped'      => $mapped,
207
                        'constraints' => $constraints,
208
                    ];
209
210
                    $emptyValue = '';
211
                    if (in_array($type, [SelectType::class, MultiselectType::class]) && !empty($properties['list'])) {
212
                        $typeProperties['choices']      = array_flip(FormFieldHelper::parseList($properties['list']));
213
                        $cleaningRules[$field['alias']] = 'raw';
214
                    }
215
                    if (BooleanType::class === $type && !empty($properties['yes']) && !empty($properties['no'])) {
216
                        $typeProperties['yes_label'] = $properties['yes'];
217
                        $typeProperties['no_label']  = $properties['no'];
218
                        $emptyValue                  = ' x ';
219
                        if ('' !== $value && null !== $value) {
220
                            $value = (int) $value;
221
                        }
222
                    }
223
224
                    $typeProperties['data']        = MultiselectType::class === $type ? FormFieldHelper::parseList($value) : $value;
225
                    $typeProperties['placeholder'] = $emptyValue;
226
                    $builder->add(
227
                        $alias,
228
                        $type,
229
                        $typeProperties
230
                    );
231
                    break;
232
                case CountryType::class:
233
                case RegionType::class:
234
                case TimezoneType::class:
235
                case LocaleType::class:
236
                    $builder->add(
237
                        $alias,
238
                        $type,
239
                        [
240
                            'required'          => $required,
241
                            'label'             => $field['label'],
242
                            'data'              => $value,
243
                            'attr'              => [
244
                                'class'            => 'form-control',
245
                                'data-placeholder' => $field['label'],
246
                            ],
247
                            'mapped'      => $mapped,
248
                            'constraints' => $constraints,
249
                        ]
250
                    );
251
                    break;
252
                default:
253
                    $attr['data-encoding'] = 'raw';
254
                    switch ($type) {
255
                        case LookupType::class:
256
                            $attr['data-target'] = $alias;
257
                            if (!empty($properties['list'])) {
258
                                $attr['data-options'] = FormFieldHelper::formatList(FormFieldHelper::FORMAT_BAR, array_keys(FormFieldHelper::parseList($properties['list'])));
259
                            }
260
                            break;
261
                        case EmailType::class:
262
                            // Enforce a valid email
263
                            $attr['data-encoding'] = 'email';
264
                            $constraints[]         = new Email(
265
                                [
266
                                    'message' => 'mautic.core.email.required',
267
                                ]
268
                            );
269
                            break;
270
                        case TextType::class:
271
                            $constraints[] = new Length(['max' => 191]);
272
                            break;
273
274
                        case MultiselectType::class:
275
                            $constraints[] = new Length(['max' => 65535]);
276
                            break;
277
                    }
278
279
                    $builder->add(
280
                        $alias,
281
                        $type,
282
                        [
283
                            'required'    => $field['isRequired'],
284
                            'label'       => $field['label'],
285
                            'label_attr'  => ['class' => 'control-label'],
286
                            'attr'        => $attr,
287
                            'data'        => $value,
288
                            'mapped'      => $mapped,
289
                            'constraints' => $constraints,
290
                        ]
291
                    );
292
                    break;
293
            }
294
        }
295
296
        return $cleaningRules;
297
    }
298
}
299