Issues (3627)

bundles/FormBundle/Controller/FormController.php (1 issue)

1
<?php
2
3
/*
4
 * @copyright   2014 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\FormBundle\Controller;
13
14
use Mautic\CoreBundle\Controller\FormController as CommonFormController;
15
use Mautic\CoreBundle\Factory\PageHelperFactoryInterface;
16
use Mautic\CoreBundle\Form\Type\DateRangeType;
17
use Mautic\FormBundle\Entity\Field;
18
use Mautic\FormBundle\Entity\Form;
19
use Mautic\FormBundle\Exception\ValidationException;
20
use Mautic\FormBundle\Helper\FormFieldHelper;
21
use Mautic\FormBundle\Model\FormModel;
22
use Symfony\Component\Form\FormError;
23
use Symfony\Component\HttpFoundation\Response;
24
25
class FormController extends CommonFormController
26
{
27
    /**
28
     * @param int $page
29
     *
30
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|Response
31
     */
32
    public function indexAction($page = 1)
33
    {
34
        //set some permissions
35
        $permissions = $this->get('mautic.security')->isGranted(
36
            [
37
                'form:forms:viewown',
38
                'form:forms:viewother',
39
                'form:forms:create',
40
                'form:forms:editown',
41
                'form:forms:editother',
42
                'form:forms:deleteown',
43
                'form:forms:deleteother',
44
                'form:forms:publishown',
45
                'form:forms:publishother',
46
            ],
47
            'RETURN_ARRAY'
48
        );
49
50
        if (!$permissions['form:forms:viewown'] && !$permissions['form:forms:viewother']) {
51
            return $this->accessDenied();
52
        }
53
54
        $this->setListFilters();
55
56
        $session = $this->get('session');
57
58
        /** @var PageHelperFactoryInterface $pageHelperFacotry */
59
        $pageHelperFacotry = $this->get('mautic.page.helper.factory');
60
        $pageHelper        = $pageHelperFacotry->make('mautic.form', $page);
61
        $limit             = $pageHelper->getLimit();
62
        $start             = $pageHelper->getStart();
63
        $search            = $this->request->get('search', $session->get('mautic.form.filter', ''));
64
        $filter            = ['string' => $search, 'force' => []];
65
        $session->set('mautic.form.filter', $search);
66
67
        if (!$permissions['form:forms:viewother']) {
68
            $filter['force'][] = ['column' => 'f.createdBy', 'expr' => 'eq', 'value' => $this->user->getId()];
69
        }
70
71
        $orderBy    = $session->get('mautic.form.orderby', 'f.name');
72
        $orderByDir = $session->get('mautic.form.orderbydir', 'ASC');
73
        $forms      = $this->getModel('form.form')->getEntities(
74
            [
75
                'start'      => $start,
76
                'limit'      => $limit,
77
                'filter'     => $filter,
78
                'orderBy'    => $orderBy,
79
                'orderByDir' => $orderByDir,
80
            ]
81
        );
82
83
        $count = count($forms);
84
85
        if ($count && $count < ($start + 1)) {
86
            //the number of entities are now less then the current page so redirect to the last page
87
            $lastPage = $pageHelper->countPage($count);
88
            $pageHelper->rememberPage($lastPage);
89
            $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $lastPage]);
90
91
            return $this->postActionRedirect(
92
                [
93
                    'returnUrl'       => $returnUrl,
94
                    'viewParameters'  => ['page' => $lastPage],
95
                    'contentTemplate' => 'MauticFormBundle:Form:index',
96
                    'passthroughVars' => [
97
                        'activeLink'    => '#mautic_form_index',
98
                        'mauticContent' => 'form',
99
                    ],
100
                ]
101
            );
102
        }
103
104
        $pageHelper->rememberPage($page);
105
106
        return $this->delegateView(
107
            [
108
                'viewParameters'  => [
109
                    'searchValue' => $search,
110
                    'items'       => $forms,
111
                    'totalItems'  => $count,
112
                    'page'        => $page,
113
                    'limit'       => $limit,
114
                    'permissions' => $permissions,
115
                    'security'    => $this->get('mautic.security'),
116
                    'tmpl'        => $this->request->get('tmpl', 'index'),
117
                ],
118
                'contentTemplate' => 'MauticFormBundle:Form:list.html.php',
119
                'passthroughVars' => [
120
                    'activeLink'    => '#mautic_form_index',
121
                    'mauticContent' => 'form',
122
                    'route'         => $this->generateUrl('mautic_form_index', ['page' => $page]),
123
                ],
124
            ]
125
        );
126
    }
127
128
    /**
129
     * Loads a specific form into the detailed panel.
130
     *
131
     * @param int $objectId
132
     *
133
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|Response
134
     */
135
    public function viewAction($objectId)
136
    {
137
        /** @var \Mautic\FormBundle\Model\FormModel $model */
138
        $model      = $this->getModel('form');
139
        $activeForm = $model->getEntity($objectId);
140
141
        //set the page we came from
142
        $page = $this->get('session')->get('mautic.form.page', 1);
143
144
        if (null === $activeForm) {
145
            //set the return URL
146
            $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $page]);
147
148
            return $this->postActionRedirect(
149
                [
150
                    'returnUrl'       => $returnUrl,
151
                    'viewParameters'  => ['page' => $page],
152
                    'contentTemplate' => 'MauticFormBundle:Form:index',
153
                    'passthroughVars' => [
154
                        'activeLink'    => '#mautic_form_index',
155
                        'mauticContent' => 'form',
156
                    ],
157
                    'flashes' => [
158
                        [
159
                            'type'    => 'error',
160
                            'msg'     => 'mautic.form.error.notfound',
161
                            'msgVars' => ['%id%' => $objectId],
162
                        ],
163
                    ],
164
                ]
165
            );
166
        } elseif (!$this->get('mautic.security')->hasEntityAccess(
167
            'form:forms:viewown',
168
            'form:forms:viewother',
169
            $activeForm->getCreatedBy()
170
        )
171
        ) {
172
            return $this->accessDenied();
173
        }
174
175
        $permissions = $this->get('mautic.security')->isGranted(
176
            [
177
                'form:forms:viewown',
178
                'form:forms:viewother',
179
                'form:forms:create',
180
                'form:forms:editown',
181
                'form:forms:editother',
182
                'form:forms:deleteown',
183
                'form:forms:deleteother',
184
                'form:forms:publishown',
185
                'form:forms:publishother',
186
            ],
187
            'RETURN_ARRAY'
188
        );
189
190
        // Audit Log
191
        $logs = $this->getModel('core.auditlog')->getLogForObject('form', $objectId, $activeForm->getDateAdded());
192
193
        // Init the date range filter form
194
        $dateRangeValues = $this->request->get('daterange', []);
195
        $action          = $this->generateUrl('mautic_form_action', ['objectAction' => 'view', 'objectId' => $objectId]);
196
        $dateRangeForm   = $this->get('form.factory')->create(DateRangeType::class, $dateRangeValues, ['action' => $action]);
197
198
        // Submission stats per time period
199
        $timeStats = $this->getModel('form.submission')->getSubmissionsLineChartData(
200
            null,
201
            new \DateTime($dateRangeForm->get('date_from')->getData()),
202
            new \DateTime($dateRangeForm->get('date_to')->getData()),
203
            null,
204
            ['form_id' => $objectId]
205
        );
206
207
        // Only show actions and fields that still exist
208
        $customComponents  = $model->getCustomComponents();
209
        $activeFormActions = [];
210
        foreach ($activeForm->getActions() as $formAction) {
211
            if (!isset($customComponents['actions'][$formAction->getType()])) {
212
                continue;
213
            }
214
            $type                          = explode('.', $formAction->getType());
215
            $activeFormActions[$type[0]][] = $formAction;
216
        }
217
218
        $activeFormFields = [];
219
        $fieldHelper      = $this->get('mautic.helper.form.field_helper');
220
        $availableFields  = array_flip($fieldHelper->getChoiceList($customComponents['fields']));
221
        foreach ($activeForm->getFields() as $field) {
222
            if (!isset($availableFields[$field->getType()])) {
223
                continue;
224
            }
225
226
            $activeFormFields[] = $field;
227
        }
228
229
        $submissionCounts = $this->getModel('form.submission')->getRepository()->getSubmissionCounts($activeForm);
0 ignored issues
show
The method getSubmissionCounts() does not exist on Mautic\CoreBundle\Entity\CommonRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

229
        $submissionCounts = $this->getModel('form.submission')->getRepository()->/** @scrutinizer ignore-call */ getSubmissionCounts($activeForm);
Loading history...
230
231
        return $this->delegateView(
232
            [
233
                'viewParameters' => [
234
                    'activeForm'       => $activeForm,
235
                    'submissionCounts' => $submissionCounts,
236
                    'page'             => $page,
237
                    'logs'             => $logs,
238
                    'permissions'      => $permissions,
239
                    'stats'            => [
240
                        'submissionsInTime' => $timeStats,
241
                    ],
242
                    'dateRangeForm'     => $dateRangeForm->createView(),
243
                    'activeFormActions' => $activeFormActions,
244
                    'activeFormFields'  => $activeFormFields,
245
                    'formScript'        => htmlspecialchars($model->getFormScript($activeForm), ENT_QUOTES, 'UTF-8'),
246
                    'formContent'       => htmlspecialchars($model->getContent($activeForm, false), ENT_QUOTES, 'UTF-8'),
247
                    'availableActions'  => $customComponents['actions'],
248
                ],
249
                'contentTemplate' => 'MauticFormBundle:Form:details.html.php',
250
                'passthroughVars' => [
251
                    'activeLink'    => '#mautic_form_index',
252
                    'mauticContent' => 'form',
253
                    'route'         => $action,
254
                ],
255
            ]
256
        );
257
    }
258
259
    /**
260
     * Generates new form and processes post data.
261
     *
262
     * @return array|\Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|Response
263
     *
264
     * @throws \Exception
265
     */
266
    public function newAction()
267
    {
268
        /** @var \Mautic\FormBundle\Model\FormModel $model */
269
        $model   = $this->getModel('form');
270
        $entity  = $model->getEntity();
271
        $session = $this->get('session');
272
273
        if (!$this->get('mautic.security')->isGranted('form:forms:create')) {
274
            return $this->accessDenied();
275
        }
276
277
        //set the page we came from
278
        $page       = $this->get('session')->get('mautic.form.page', 1);
279
        $mauticform = $this->request->request->get('mauticform', []);
280
        $sessionId  = $mauticform['sessionId'] ?? 'mautic_'.sha1(uniqid(mt_rand(), true));
281
282
        //set added/updated fields
283
        $modifiedFields = $session->get('mautic.form.'.$sessionId.'.fields.modified', []);
284
        $deletedFields  = $session->get('mautic.form.'.$sessionId.'.fields.deleted', []);
285
286
        //set added/updated actions
287
        $modifiedActions = $session->get('mautic.form.'.$sessionId.'.actions.modified', []);
288
        $deletedActions  = $session->get('mautic.form.'.$sessionId.'.actions.deleted', []);
289
290
        $action = $this->generateUrl('mautic_form_action', ['objectAction' => 'new']);
291
        $form   = $model->createForm($entity, $this->get('form.factory'), $action);
292
293
        ///Check for a submitted form and process it
294
        if ('POST' == $this->request->getMethod()) {
295
            $valid = false;
296
            if (!$cancelled = $this->isFormCancelled($form)) {
297
                if ($valid = $this->isFormValid($form)) {
298
                    //only save fields that are not to be deleted
299
                    $fields = array_diff_key($modifiedFields, array_flip($deletedFields));
300
301
                    //make sure that at least one field is selected
302
                    if (empty($fields)) {
303
                        //set the error
304
                        $form->addError(
305
                            new FormError(
306
                                $this->get('translator')->trans('mautic.form.form.fields.notempty', [], 'validators')
307
                            )
308
                        );
309
                        $valid = false;
310
                    } else {
311
                        $model->setFields($entity, $fields);
312
313
                        try {
314
                            // Set alias to prevent SQL errors
315
                            $alias = $model->cleanAlias($entity->getName(), '', 10);
316
                            $entity->setAlias($alias);
317
318
                            // Set timestamps
319
                            $model->setTimestamps($entity, true, false);
320
321
                            // Save the form first and new actions so that new fields are available to actions.
322
                            // Using the repository function to not trigger the listeners twice.
323
324
                            $model->getRepository()->saveEntity($entity);
325
326
                            // Only save actions that are not to be deleted
327
                            $actions = array_diff_key($modifiedActions, array_flip($deletedActions));
328
329
                            // Set and persist actions
330
                            $model->setActions($entity, $actions);
331
332
                            // Save and trigger listeners
333
                            $model->saveEntity($entity, $form->get('buttons')->get('save')->isClicked());
334
335
                            $this->addFlash(
336
                                'mautic.core.notice.created',
337
                                [
338
                                    '%name%'      => $entity->getName(),
339
                                    '%menu_link%' => 'mautic_form_index',
340
                                    '%url%'       => $this->generateUrl(
341
                                        'mautic_form_action',
342
                                        [
343
                                            'objectAction' => 'edit',
344
                                            'objectId'     => $entity->getId(),
345
                                        ]
346
                                    ),
347
                                ]
348
                            );
349
350
                            if ($form->get('buttons')->get('save')->isClicked()) {
351
                                $viewParameters = [
352
                                    'objectAction' => 'view',
353
                                    'objectId'     => $entity->getId(),
354
                                ];
355
                                $returnUrl = $this->generateUrl('mautic_form_action', $viewParameters);
356
                                $template  = 'MauticFormBundle:Form:view';
357
                            } else {
358
                                //return edit view so that all the session stuff is loaded
359
                                return $this->editAction($entity->getId(), true);
360
                            }
361
                        } catch (ValidationException $ex) {
362
                            $form->addError(
363
                                new FormError(
364
                                    $ex->getMessage()
365
                                )
366
                            );
367
                            $valid = false;
368
                        } catch (\Exception $e) {
369
                            $form['name']->addError(
370
                                new FormError($this->get('translator')->trans('mautic.form.schema.failed', [], 'validators'))
371
                            );
372
                            $valid = false;
373
374
                            if ('dev' == $this->container->getParameter('kernel.environment')) {
375
                                throw $e;
376
                            }
377
                        }
378
                    }
379
                }
380
            } else {
381
                $viewParameters = ['page' => $page];
382
                $returnUrl      = $this->generateUrl('mautic_form_index', $viewParameters);
383
                $template       = 'MauticFormBundle:Form:index';
384
            }
385
386
            if ($cancelled || ($valid && $form->get('buttons')->get('save')->isClicked())) {
387
                //clear temporary fields
388
                $this->clearSessionComponents($sessionId);
389
390
                return $this->postActionRedirect(
391
                    [
392
                        'returnUrl'       => $returnUrl,
393
                        'viewParameters'  => $viewParameters,
394
                        'contentTemplate' => $template,
395
                        'passthroughVars' => [
396
                            'activeLink'    => '#mautic_form_index',
397
                            'mauticContent' => 'form',
398
                        ],
399
                    ]
400
                );
401
            }
402
        } else {
403
            //clear out existing fields in case the form was refreshed, browser closed, etc
404
            $this->clearSessionComponents($sessionId);
405
            $modifiedFields = $modifiedActions = $deletedActions = $deletedFields = [];
406
407
            $form->get('sessionId')->setData($sessionId);
408
409
            //add a submit button
410
            $keyId = 'new'.hash('sha1', uniqid(mt_rand()));
411
            $field = new Field();
412
413
            $modifiedFields[$keyId]                    = $field->convertToArray();
414
            $modifiedFields[$keyId]['label']           = $this->translator->trans('mautic.core.form.submit');
415
            $modifiedFields[$keyId]['alias']           = 'submit';
416
            $modifiedFields[$keyId]['showLabel']       = 1;
417
            $modifiedFields[$keyId]['type']            = 'button';
418
            $modifiedFields[$keyId]['id']              = $keyId;
419
            $modifiedFields[$keyId]['inputAttributes'] = 'class="btn btn-default"';
420
            $modifiedFields[$keyId]['formId']          = $sessionId;
421
            unset($modifiedFields[$keyId]['form']);
422
            $session->set('mautic.form.'.$sessionId.'.fields.modified', $modifiedFields);
423
        }
424
425
        //fire the form builder event
426
        $customComponents = $model->getCustomComponents($sessionId);
427
428
        /** @var FormFieldHelper $fieldHelper */
429
        $fieldHelper = $this->get('mautic.helper.form.field_helper');
430
431
        return $this->delegateView(
432
            [
433
                'viewParameters' => [
434
                    'fields'         => $fieldHelper->getChoiceList($customComponents['fields']),
435
                    'actions'        => $customComponents['choices'],
436
                    'actionSettings' => $customComponents['actions'],
437
                    'formFields'     => $modifiedFields,
438
                    'formActions'    => $modifiedActions,
439
                    'deletedFields'  => $deletedFields,
440
                    'deletedActions' => $deletedActions,
441
                    'tmpl'           => $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index',
442
                    'activeForm'     => $entity,
443
                    'form'           => $form->createView(),
444
                    'contactFields'  => $this->getModel('lead.field')->getFieldListWithProperties(),
445
                    'companyFields'  => $this->getModel('lead.field')->getFieldListWithProperties('company'),
446
                    'inBuilder'      => true,
447
                ],
448
                'contentTemplate' => 'MauticFormBundle:Builder:index.html.php',
449
                'passthroughVars' => [
450
                    'activeLink'    => '#mautic_form_index',
451
                    'mauticContent' => 'form',
452
                    'route'         => $this->generateUrl(
453
                        'mautic_form_action',
454
                        [
455
                            'objectAction' => (!empty($valid) ? 'edit' : 'new'), //valid means a new form was applied
456
                            'objectId'     => $entity->getId(),
457
                        ]
458
                    ),
459
                ],
460
            ]
461
        );
462
    }
463
464
    /**
465
     * Generates edit form and processes post data.
466
     *
467
     * @param int  $objectId
468
     * @param bool $ignorePost
469
     * @param bool $forceTypeSelection
470
     *
471
     * @return \Symfony\Component\HttpFoundation\JsonResponse|Response
472
     */
473
    public function editAction($objectId, $ignorePost = false, $forceTypeSelection = false)
474
    {
475
        /** @var \Mautic\FormBundle\Model\FormModel $model */
476
        $model            = $this->getModel('form');
477
        $formData         = $this->request->request->get('mauticform');
478
        $sessionId        = isset($formData['sessionId']) ? $formData['sessionId'] : null;
479
        $customComponents = $model->getCustomComponents();
480
481
        if ($objectId instanceof Form) {
482
            $entity   = $objectId;
483
            $objectId = 'mautic_'.sha1(uniqid(mt_rand(), true));
484
        } else {
485
            $entity = $model->getEntity($objectId);
486
487
            // Process submit of cloned form
488
            if (null == $entity && $objectId == $sessionId) {
489
                $entity = $model->getEntity();
490
            }
491
        }
492
493
        $session    = $this->get('session');
494
        $cleanSlate = true;
495
496
        //set the page we came from
497
        $page = $this->get('session')->get('mautic.form.page', 1);
498
499
        //set the return URL
500
        $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $page]);
501
502
        $postActionVars = [
503
            'returnUrl'       => $returnUrl,
504
            'viewParameters'  => ['page' => $page],
505
            'contentTemplate' => 'MauticFormBundle:Form:index',
506
            'passthroughVars' => [
507
                'activeLink'    => '#mautic_form_index',
508
                'mauticContent' => 'form',
509
            ],
510
        ];
511
512
        //form not found
513
        if (null === $entity) {
514
            return $this->postActionRedirect(
515
                array_merge(
516
                    $postActionVars,
517
                    [
518
                        'flashes' => [
519
                            [
520
                                'type'    => 'error',
521
                                'msg'     => 'mautic.form.error.notfound',
522
                                'msgVars' => ['%id%' => $objectId],
523
                            ],
524
                        ],
525
                    ]
526
                )
527
            );
528
        } elseif (!$this->get('mautic.security')->hasEntityAccess(
529
            'form:forms:editown',
530
            'form:forms:editother',
531
            $entity->getCreatedBy()
532
        )
533
        ) {
534
            return $this->accessDenied();
535
        } elseif ($model->isLocked($entity)) {
536
            //deny access if the entity is locked
537
            return $this->isLocked($postActionVars, $entity, 'form.form');
538
        }
539
540
        $action = $this->generateUrl('mautic_form_action', ['objectAction' => 'edit', 'objectId' => $objectId]);
541
        $form   = $model->createForm($entity, $this->get('form.factory'), $action);
542
543
        ///Check for a submitted form and process it
544
        if (!$ignorePost && 'POST' == $this->request->getMethod()) {
545
            $valid = false;
546
            if (!$cancelled = $this->isFormCancelled($form)) {
547
                //set added/updated fields
548
                $modifiedFields = $session->get('mautic.form.'.$objectId.'.fields.modified', []);
549
                $deletedFields  = $session->get('mautic.form.'.$objectId.'.fields.deleted', []);
550
                $fields         = array_diff_key($modifiedFields, array_flip($deletedFields));
551
552
                //set added/updated actions
553
                $modifiedActions = $session->get('mautic.form.'.$objectId.'.actions.modified', []);
554
                $deletedActions  = $session->get('mautic.form.'.$objectId.'.actions.deleted', []);
555
                $actions         = array_diff_key($modifiedActions, array_flip($deletedActions));
556
557
                if ($valid = $this->isFormValid($form)) {
558
                    //make sure that at least one field is selected
559
                    if (empty($fields)) {
560
                        //set the error
561
                        $form->addError(
562
                            new FormError(
563
                                $this->get('translator')->trans('mautic.form.form.fields.notempty', [], 'validators')
564
                            )
565
                        );
566
                        $valid = false;
567
                    } else {
568
                        $model->setFields($entity, $fields);
569
                        $model->deleteFields($entity, $deletedFields);
570
571
                        $alias = $entity->getAlias();
572
573
                        if (empty($alias)) {
574
                            $alias = $model->cleanAlias($entity->getName(), '', 10);
575
                            $entity->setAlias($alias);
576
                        }
577
578
                        if (!$entity->getId()) {
579
                            // Set timestamps because this is a new clone
580
                            $model->setTimestamps($entity, true, false);
581
                        }
582
583
                        // save the form first so that new fields are available to actions
584
                        // use the repository method to not trigger listeners twice
585
                        try {
586
                            $model->getRepository()->saveEntity($entity);
587
588
                            // Ensure actions are compatible with form type
589
                            if (!$entity->isStandalone()) {
590
                                foreach ($actions as $actionId => $action) {
591
                                    if (empty($customComponents['actions'][$action['type']]['allowCampaignForm'])) {
592
                                        unset($actions[$actionId]);
593
                                        $deletedActions[] = $actionId;
594
                                    }
595
                                }
596
                            }
597
598
                            if (count($actions)) {
599
                                // Now set and persist the actions
600
                                $model->setActions($entity, $actions);
601
                            }
602
603
                            // Delete deleted actions
604
                            $model->deleteActions($entity, $deletedActions);
605
606
                            // Persist and execute listeners
607
                            $model->saveEntity($entity, $form->get('buttons')->get('save')->isClicked());
608
609
                            // Reset objectId to entity ID (can be session ID in case of cloned entity)
610
                            $objectId = $entity->getId();
611
612
                            $this->addFlash(
613
                                'mautic.core.notice.updated',
614
                                [
615
                                    '%name%'      => $entity->getName(),
616
                                    '%menu_link%' => 'mautic_form_index',
617
                                    '%url%'       => $this->generateUrl(
618
                                        'mautic_form_action',
619
                                        [
620
                                            'objectAction' => 'edit',
621
                                            'objectId'     => $entity->getId(),
622
                                        ]
623
                                    ),
624
                                ]
625
                            );
626
627
                            if ($form->get('buttons')->get('save')->isClicked()) {
628
                                $viewParameters = [
629
                                    'objectAction' => 'view',
630
                                    'objectId'     => $entity->getId(),
631
                                ];
632
                                $returnUrl = $this->generateUrl('mautic_form_action', $viewParameters);
633
                                $template  = 'MauticFormBundle:Form:view';
634
                            }
635
                        } catch (ValidationException $ex) {
636
                            $form->addError(
637
                                new FormError(
638
                                    $ex->getMessage()
639
                                )
640
                            );
641
                            $valid = false;
642
                        }
643
                    }
644
                }
645
            } else {
646
                //unlock the entity
647
                $model->unlockEntity($entity);
648
649
                $viewParameters = ['page' => $page];
650
                $returnUrl      = $this->generateUrl('mautic_form_index', $viewParameters);
651
                $template       = 'MauticFormBundle:Form:index';
652
            }
653
654
            if ($cancelled || ($valid && $form->get('buttons')->get('save')->isClicked())) {
655
                //remove fields from session
656
                $this->clearSessionComponents($objectId);
657
658
                // Clear session items in case columns changed
659
                $session->remove('mautic.formresult.'.$entity->getId().'.orderby');
660
                $session->remove('mautic.formresult.'.$entity->getId().'.orderbydir');
661
                $session->remove('mautic.formresult.'.$entity->getId().'.filters');
662
663
                return $this->postActionRedirect(
664
                    array_merge(
665
                        $postActionVars,
666
                        [
667
                            'returnUrl'       => $returnUrl,
668
                            'viewParameters'  => $viewParameters,
669
                            'contentTemplate' => $template,
670
                        ]
671
                    )
672
                );
673
            } elseif ($valid && $form->get('buttons')->get('apply')->isClicked()) {
674
                // Rebuild everything to include new ids
675
                $cleanSlate = true;
676
                $reorder    = true;
677
678
                if ($valid) {
679
                    // Rebuild the form with new action so that apply doesn't keep creating a clone
680
                    $action = $this->generateUrl('mautic_form_action', ['objectAction' => 'edit', 'objectId' => $entity->getId()]);
681
                    $form   = $model->createForm($entity, $this->get('form.factory'), $action);
682
                }
683
            }
684
        } else {
685
            $cleanSlate = true;
686
687
            //lock the entity
688
            $model->lockEntity($entity);
689
        }
690
691
        if (!$form->isSubmitted()) {
692
            $form->get('sessionId')->setData($objectId);
693
        }
694
695
        // Get field and action settings
696
        $fieldHelper     = $this->get('mautic.helper.form.field_helper');
697
        $availableFields = $fieldHelper->getChoiceList($customComponents['fields']);
698
699
        if ($cleanSlate) {
700
            //clean slate
701
            $this->clearSessionComponents($objectId);
702
703
            //load existing fields into session
704
            $modifiedFields    = [];
705
            $usedLeadFields    = [];
706
            $usedCompanyFields = [];
707
            $existingFields    = $entity->getFields()->toArray();
708
            $submitButton      = false;
709
710
            foreach ($existingFields as $formField) {
711
                // Check to see if the field still exists
712
713
                if ('button' == $formField->getType()) {
714
                    //submit button found
715
                    $submitButton = true;
716
                }
717
                if ('button' !== $formField->getType() && !in_array($formField->getType(), $availableFields)) {
718
                    continue;
719
                }
720
721
                $id    = $formField->getId();
722
                $field = $formField->convertToArray();
723
724
                if (!$id) {
725
                    // Cloned entity
726
                    $id = $field['id'] = $field['sessionId'] = 'new'.hash('sha1', uniqid(mt_rand()));
727
                }
728
729
                unset($field['form']);
730
731
                if (isset($customComponents['fields'][$field['type']])) {
732
                    // Set the custom parameters
733
                    $field['customParameters'] = $customComponents['fields'][$field['type']];
734
                }
735
                $field['formId'] = $objectId;
736
737
                $modifiedFields[$id] = $field;
738
739
                if (!empty($field['leadField'])) {
740
                    $usedLeadFields[$id] = $field['leadField'];
741
                }
742
            }
743
            if (!$submitButton) { //means something deleted the submit button from the form
744
                //add a submit button
745
                $keyId = 'new'.hash('sha1', uniqid(mt_rand()));
746
                $field = new Field();
747
748
                $modifiedFields[$keyId]                    = $field->convertToArray();
749
                $modifiedFields[$keyId]['label']           = $this->translator->trans('mautic.core.form.submit');
750
                $modifiedFields[$keyId]['alias']           = 'submit';
751
                $modifiedFields[$keyId]['showLabel']       = 1;
752
                $modifiedFields[$keyId]['type']            = 'button';
753
                $modifiedFields[$keyId]['id']              = $keyId;
754
                $modifiedFields[$keyId]['inputAttributes'] = 'class="btn btn-default"';
755
                $modifiedFields[$keyId]['formId']          = $objectId;
756
                unset($modifiedFields[$keyId]['form']);
757
            }
758
            $session->set('mautic.form.'.$objectId.'.fields.leadfields', $usedLeadFields);
759
760
            if (!empty($reorder)) {
761
                uasort(
762
                    $modifiedFields,
763
                    function ($a, $b) {
764
                        return $a['order'] > $b['order'];
765
                    }
766
                );
767
            }
768
769
            $session->set('mautic.form.'.$objectId.'.fields.modified', $modifiedFields);
770
            $deletedFields = [];
771
772
            // Load existing actions into session
773
            $modifiedActions = [];
774
            $existingActions = $entity->getActions()->toArray();
775
776
            foreach ($existingActions as $formAction) {
777
                // Check to see if the action still exists
778
                if (!isset($customComponents['actions'][$formAction->getType()])) {
779
                    continue;
780
                }
781
782
                $id     = $formAction->getId();
783
                $action = $formAction->convertToArray();
784
785
                if (!$id) {
786
                    // Cloned entity so use a random Id instead
787
                    $action['id'] = $id = 'new'.hash('sha1', uniqid(mt_rand()));
788
                }
789
                unset($action['form']);
790
791
                $modifiedActions[$id] = $action;
792
            }
793
794
            if (!empty($reorder)) {
795
                uasort(
796
                    $modifiedActions,
797
                    function ($a, $b) {
798
                        return $a['order'] > $b['order'];
799
                    }
800
                );
801
            }
802
803
            $session->set('mautic.form.'.$objectId.'.actions.modified', $modifiedActions);
804
            $deletedActions = [];
805
        }
806
807
        return $this->delegateView(
808
            [
809
                'viewParameters' => [
810
                    'fields'             => $availableFields,
811
                    'actions'            => $customComponents['choices'],
812
                    'actionSettings'     => $customComponents['actions'],
813
                    'formFields'         => $modifiedFields,
814
                    'fieldSettings'      => $customComponents['fields'],
815
                    'formActions'        => $modifiedActions,
816
                    'deletedFields'      => $deletedFields,
817
                    'deletedActions'     => $deletedActions,
818
                    'tmpl'               => $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index',
819
                    'activeForm'         => $entity,
820
                    'form'               => $form->createView(),
821
                    'forceTypeSelection' => $forceTypeSelection,
822
                    'contactFields'      => $this->getModel('lead.field')->getFieldListWithProperties('lead'),
823
                    'companyFields'      => $this->getModel('lead.field')->getFieldListWithProperties('company'),
824
                    'inBuilder'          => true,
825
                ],
826
                'contentTemplate' => 'MauticFormBundle:Builder:index.html.php',
827
                'passthroughVars' => [
828
                    'activeLink'    => '#mautic_form_index',
829
                    'mauticContent' => 'form',
830
                    'route'         => $this->generateUrl(
831
                        'mautic_form_action',
832
                        [
833
                            'objectAction' => 'edit',
834
                            'objectId'     => $entity->getId(),
835
                        ]
836
                    ),
837
                ],
838
            ]
839
        );
840
    }
841
842
    /**
843
     * Clone an entity.
844
     *
845
     * @param int $objectId
846
     *
847
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|Response
848
     */
849
    public function cloneAction($objectId)
850
    {
851
        $model = $this->getModel('form.form');
852
853
        /** @var \Mautic\FormBundle\Entity\Form $entity */
854
        $entity = $model->getEntity($objectId);
855
856
        if (null != $entity) {
857
            if (!$this->get('mautic.security')->isGranted('form:forms:create')
858
                || !$this->get('mautic.security')->hasEntityAccess(
859
                    'form:forms:viewown',
860
                    'form:forms:viewother',
861
                    $entity->getCreatedBy()
862
                )
863
            ) {
864
                return $this->accessDenied();
865
            }
866
867
            $entity = clone $entity;
868
            $entity->setIsPublished(false);
869
870
            // Clone the forms's fields
871
            $fields = $entity->getFields()->toArray();
872
            /** @var \Mautic\FormBundle\Entity\Field $field */
873
            foreach ($fields as $field) {
874
                $fieldClone = clone $field;
875
                $fieldClone->setForm($entity);
876
                $fieldClone->setSessionId(null);
877
                $entity->addField($field->getId(), $fieldClone);
878
            }
879
880
            // Clone the forms's actions
881
            $actions = $entity->getActions()->toArray();
882
            /** @var \Mautic\FormBundle\Entity\Action $action */
883
            foreach ($actions as $action) {
884
                $actionClone = clone $action;
885
                $actionClone->setForm($entity);
886
                $entity->addAction($action->getId(), $actionClone);
887
            }
888
        }
889
890
        return $this->editAction($entity, true, true);
891
    }
892
893
    /**
894
     * Gives a preview of the form.
895
     *
896
     * @param int $objectId
897
     *
898
     * @return Response
899
     */
900
    public function previewAction($objectId)
901
    {
902
        /** @var FormModel $model */
903
        $model = $this->getModel('form.form');
904
        $form  = $model->getEntity($objectId);
905
906
        if (null === $form) {
907
            $html =
908
                '<h1>'.
909
                $this->get('translator')->trans('mautic.form.error.notfound', ['%id%' => $objectId], 'flashes').
910
                '</h1>';
911
        } elseif (!$this->get('mautic.security')->hasEntityAccess(
912
            'form:forms:editown',
913
            'form:forms:editother',
914
            $form->getCreatedBy()
915
        )
916
        ) {
917
            $html = '<h1>'.$this->get('translator')->trans('mautic.core.error.accessdenied', [], 'flashes').'</h1>';
918
        } else {
919
            $html = $model->getContent($form, true, false);
920
        }
921
922
        $model->populateValuesWithGetParameters($form, $html);
923
924
        $viewParams = [
925
            'content'     => $html,
926
            'stylesheets' => [],
927
            'name'        => $form->getName(),
928
            'metaRobots'  => '<meta name="robots" content="index">',
929
        ];
930
931
        if ($form->getNoIndex()) {
932
            $viewParams['metaRobots'] = '<meta name="robots" content="noindex">';
933
        }
934
935
        $template = $form->getTemplate();
936
        if (!empty($template)) {
937
            $theme = $this->get('mautic.helper.theme')->getTheme($template);
938
            if ($theme->getTheme() != $template) {
939
                $config = $theme->getConfig();
940
                if (in_array('form', $config['features'])) {
941
                    $template = $theme->getTheme();
942
                } else {
943
                    $template = null;
944
                }
945
            }
946
        }
947
948
        $viewParams['template'] = $template;
949
950
        if (!empty($template)) {
951
            $logicalName     = $this->get('mautic.helper.theme')->checkForTwigTemplate(':'.$template.':form.html.php');
952
            $assetsHelper    = $this->get('templating.helper.assets');
953
            $slotsHelper     = $this->get('templating.helper.slots');
954
            $analyticsHelper = $this->get('mautic.helper.template.analytics');
955
956
            if (!empty($customStylesheets)) {
957
                foreach ($customStylesheets as $css) {
958
                    $assetsHelper->addStylesheet($css);
959
                }
960
            }
961
962
            $slotsHelper->set('pageTitle', $form->getName());
963
964
            $analytics = $analyticsHelper->getCode();
965
966
            if (!empty($analytics)) {
967
                $assetsHelper->addCustomDeclaration($analytics);
968
            }
969
            if ($form->getNoIndex()) {
970
                $assetsHelper->addCustomDeclaration('<meta name="robots" content="noindex">');
971
            }
972
973
            return $this->render($logicalName, $viewParams);
974
        }
975
976
        return $this->render('MauticFormBundle::form.html.php', $viewParams);
977
    }
978
979
    /**
980
     * Deletes the entity.
981
     *
982
     * @param int $objectId
983
     *
984
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
985
     */
986
    public function deleteAction($objectId)
987
    {
988
        $page      = $this->get('session')->get('mautic.form.page', 1);
989
        $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $page]);
990
        $flashes   = [];
991
992
        $postActionVars = [
993
            'returnUrl'       => $returnUrl,
994
            'viewParameters'  => ['page' => $page],
995
            'contentTemplate' => 'MauticFormBundle:Form:index',
996
            'passthroughVars' => [
997
                'activeLink'    => '#mautic_form_index',
998
                'mauticContent' => 'form',
999
            ],
1000
        ];
1001
1002
        if ('POST' == $this->request->getMethod()) {
1003
            $model  = $this->getModel('form.form');
1004
            $entity = $model->getEntity($objectId);
1005
1006
            if (null === $entity) {
1007
                $flashes[] = [
1008
                    'type'    => 'error',
1009
                    'msg'     => 'mautic.form.error.notfound',
1010
                    'msgVars' => ['%id%' => $objectId],
1011
                ];
1012
            } elseif (!$this->get('mautic.security')->hasEntityAccess(
1013
                'form:forms:deleteown',
1014
                'form:forms:deleteother',
1015
                $entity->getCreatedBy()
1016
            )
1017
            ) {
1018
                return $this->accessDenied();
1019
            } elseif ($model->isLocked($entity)) {
1020
                return $this->isLocked($postActionVars, $entity, 'form.form');
1021
            }
1022
1023
            $model->deleteEntity($entity);
1024
1025
            $identifier = $this->get('translator')->trans($entity->getName());
1026
            $flashes[]  = [
1027
                'type'    => 'notice',
1028
                'msg'     => 'mautic.core.notice.deleted',
1029
                'msgVars' => [
1030
                    '%name%' => $identifier,
1031
                    '%id%'   => $objectId,
1032
                ],
1033
            ];
1034
        } //else don't do anything
1035
1036
        return $this->postActionRedirect(
1037
            array_merge(
1038
                $postActionVars,
1039
                [
1040
                    'flashes' => $flashes,
1041
                ]
1042
            )
1043
        );
1044
    }
1045
1046
    /**
1047
     * Deletes a group of entities.
1048
     *
1049
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
1050
     */
1051
    public function batchDeleteAction()
1052
    {
1053
        $page      = $this->get('session')->get('mautic.form.page', 1);
1054
        $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $page]);
1055
        $flashes   = [];
1056
1057
        $postActionVars = [
1058
            'returnUrl'       => $returnUrl,
1059
            'viewParameters'  => ['page' => $page],
1060
            'contentTemplate' => 'MauticFormBundle:Form:index',
1061
            'passthroughVars' => [
1062
                'activeLink'    => '#mautic_form_index',
1063
                'mauticContent' => 'form',
1064
            ],
1065
        ];
1066
1067
        if ('POST' == $this->request->getMethod()) {
1068
            $model     = $this->getModel('form');
1069
            $ids       = json_decode($this->request->query->get('ids', ''));
1070
            $deleteIds = [];
1071
1072
            // Loop over the IDs to perform access checks pre-delete
1073
            foreach ($ids as $objectId) {
1074
                $objectId = (int) $objectId;
1075
                $entity   = $model->getEntity($objectId);
1076
1077
                if (null === $entity) {
1078
                    $flashes[] = [
1079
                        'type'    => 'error',
1080
                        'msg'     => 'mautic.form.error.notfound',
1081
                        'msgVars' => ['%id%' => $objectId],
1082
                    ];
1083
                } elseif (!$this->get('mautic.security')->hasEntityAccess(
1084
                    'form:forms:deleteown',
1085
                    'form:forms:deleteother',
1086
                    $entity->getCreatedBy()
1087
                )
1088
                ) {
1089
                    $flashes[] = $this->accessDenied(true);
1090
                } elseif ($model->isLocked($entity)) {
1091
                    $flashes[] = $this->isLocked($postActionVars, $entity, 'form.form', true);
1092
                } else {
1093
                    $deleteIds[] = $objectId;
1094
                }
1095
            }
1096
1097
            // Delete everything we are able to
1098
            if (!empty($deleteIds)) {
1099
                $entities = $model->deleteEntities($deleteIds);
1100
1101
                $flashes[] = [
1102
                    'type'    => 'notice',
1103
                    'msg'     => 'mautic.form.notice.batch_deleted',
1104
                    'msgVars' => [
1105
                        '%count%' => count($entities),
1106
                    ],
1107
                ];
1108
            }
1109
        } //else don't do anything
1110
1111
        return $this->postActionRedirect(
1112
            array_merge(
1113
                $postActionVars,
1114
                [
1115
                    'flashes' => $flashes,
1116
                ]
1117
            )
1118
        );
1119
    }
1120
1121
    /**
1122
     * Clear field and actions from the session.
1123
     */
1124
    public function clearSessionComponents($sessionId)
1125
    {
1126
        $session = $this->get('session');
1127
        $session->remove('mautic.form.'.$sessionId.'.fields.modified');
1128
        $session->remove('mautic.form.'.$sessionId.'.fields.deleted');
1129
        $session->remove('mautic.form.'.$sessionId.'.fields.leadfields');
1130
1131
        $session->remove('mautic.form.'.$sessionId.'.actions.modified');
1132
        $session->remove('mautic.form.'.$sessionId.'.actions.deleted');
1133
    }
1134
1135
    public function batchRebuildHtmlAction()
1136
    {
1137
        $page      = $this->get('session')->get('mautic.form.page', 1);
1138
        $returnUrl = $this->generateUrl('mautic_form_index', ['page' => $page]);
1139
        $flashes   = [];
1140
1141
        $postActionVars = [
1142
            'returnUrl'       => $returnUrl,
1143
            'viewParameters'  => ['page' => $page],
1144
            'contentTemplate' => 'MauticFormBundle:Form:index',
1145
            'passthroughVars' => [
1146
                'activeLink'    => '#mautic_form_index',
1147
                'mauticContent' => 'form',
1148
            ],
1149
        ];
1150
1151
        if ('POST' == $this->request->getMethod()) {
1152
            /** @var \Mautic\FormBundle\Model\FormModel $model */
1153
            $model = $this->getModel('form');
1154
            $ids   = json_decode($this->request->query->get('ids', ''));
1155
            $count = 0;
1156
            // Loop over the IDs to perform access checks pre-delete
1157
            foreach ($ids as $objectId) {
1158
                $entity = $model->getEntity($objectId);
1159
1160
                if (null === $entity) {
1161
                    $flashes[] = [
1162
                        'type'    => 'error',
1163
                        'msg'     => 'mautic.form.error.notfound',
1164
                        'msgVars' => ['%id%' => $objectId],
1165
                    ];
1166
                } elseif (!$this->get('mautic.security')->hasEntityAccess(
1167
                    'form:forms:editown',
1168
                    'form:forms:editother',
1169
                    $entity->getCreatedBy()
1170
                )
1171
                ) {
1172
                    $flashes[] = $this->accessDenied(true);
1173
                } elseif ($model->isLocked($entity)) {
1174
                    $flashes[] = $this->isLocked($postActionVars, $entity, 'form.form', true);
1175
                } else {
1176
                    $model->generateHtml($entity);
1177
                    ++$count;
1178
                }
1179
            }
1180
1181
            $flashes[] = [
1182
                'type'    => 'notice',
1183
                'msg'     => 'mautic.form.notice.batch_html_generated',
1184
                'msgVars' => [
1185
                    'pluralCount' => $count,
1186
                    '%count%'     => $count,
1187
                ],
1188
            ];
1189
        } //else don't do anything
1190
1191
        return $this->postActionRedirect(
1192
            array_merge(
1193
                $postActionVars,
1194
                [
1195
                    'flashes' => $flashes,
1196
                ]
1197
            )
1198
        );
1199
    }
1200
}
1201