Issues (3627)

bundles/LeadBundle/Controller/LeadController.php (4 issues)

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\LeadBundle\Controller;
13
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Mautic\CoreBundle\Controller\FormController;
16
use Mautic\CoreBundle\Helper\EmojiHelper;
17
use Mautic\CoreBundle\Model\IteratorExportDataModel;
18
use Mautic\LeadBundle\DataObject\LeadManipulator;
19
use Mautic\LeadBundle\Deduplicate\ContactMerger;
20
use Mautic\LeadBundle\Deduplicate\Exception\SameContactException;
21
use Mautic\LeadBundle\Entity\DoNotContact;
22
use Mautic\LeadBundle\Entity\DoNotContactRepository;
23
use Mautic\LeadBundle\Entity\Lead;
24
use Mautic\LeadBundle\Form\Type\BatchType;
25
use Mautic\LeadBundle\Form\Type\DncType;
26
use Mautic\LeadBundle\Form\Type\EmailType;
27
use Mautic\LeadBundle\Form\Type\MergeType;
28
use Mautic\LeadBundle\Form\Type\OwnerType;
29
use Mautic\LeadBundle\Form\Type\StageType;
30
use Mautic\LeadBundle\Model\LeadModel;
31
use Symfony\Component\Form\FormError;
32
use Symfony\Component\HttpFoundation\File\UploadedFile;
33
use Symfony\Component\HttpFoundation\JsonResponse;
34
use Symfony\Component\HttpFoundation\Response;
35
36
class LeadController extends FormController
37
{
38
    use LeadDetailsTrait;
39
    use FrequencyRuleTrait;
40
41
    /**
42
     * @param int $page
43
     *
44
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
45
     */
46
    public function indexAction($page = 1)
47
    {
48
        //set some permissions
49
        $permissions = $this->get('mautic.security')->isGranted(
50
            [
51
                'lead:leads:viewown',
52
                'lead:leads:viewother',
53
                'lead:leads:create',
54
                'lead:leads:editown',
55
                'lead:leads:editother',
56
                'lead:leads:deleteown',
57
                'lead:leads:deleteother',
58
                'lead:imports:view',
59
                'lead:imports:create',
60
            ],
61
            'RETURN_ARRAY'
62
        );
63
64
        if (!$permissions['lead:leads:viewown'] && !$permissions['lead:leads:viewother']) {
65
            return $this->accessDenied();
66
        }
67
68
        $this->setListFilters();
69
70
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
71
        $model   = $this->getModel('lead');
72
        $session = $this->get('session');
73
        //set limits
74
        $limit = $session->get('mautic.lead.limit', $this->get('mautic.helper.core_parameters')->get('default_pagelimit'));
75
        $start = (1 === $page) ? 0 : (($page - 1) * $limit);
76
        if ($start < 0) {
77
            $start = 0;
78
        }
79
80
        $search = $this->request->get('search', $session->get('mautic.lead.filter', ''));
81
        $session->set('mautic.lead.filter', $search);
82
83
        //do some default filtering
84
        $orderBy    = $session->get('mautic.lead.orderby', 'l.last_active');
85
        $orderByDir = $session->get('mautic.lead.orderbydir', 'DESC');
86
87
        $filter      = ['string' => $search, 'force' => ''];
88
        $translator  = $this->get('translator');
89
        $anonymous   = $translator->trans('mautic.lead.lead.searchcommand.isanonymous');
90
        $listCommand = $translator->trans('mautic.lead.lead.searchcommand.list');
91
        $mine        = $translator->trans('mautic.core.searchcommand.ismine');
92
        $indexMode   = $this->request->get('view', $session->get('mautic.lead.indexmode', 'list'));
93
94
        $session->set('mautic.lead.indexmode', $indexMode);
95
96
        $anonymousShowing = false;
97
        if ('list' != $indexMode || ('list' == $indexMode && false === strpos($search, $anonymous))) {
98
            //remove anonymous leads unless requested to prevent clutter
99
            $filter['force'] .= " !$anonymous";
100
        } elseif (false !== strpos($search, $anonymous) && false === strpos($search, '!'.$anonymous)) {
101
            $anonymousShowing = true;
102
        }
103
104
        if (!$permissions['lead:leads:viewother']) {
105
            $filter['force'] .= " $mine";
106
        }
107
108
        $results = $model->getEntities([
109
            'start'          => $start,
110
            'limit'          => $limit,
111
            'filter'         => $filter,
112
            'orderBy'        => $orderBy,
113
            'orderByDir'     => $orderByDir,
114
            'withTotalCount' => true,
115
        ]);
116
117
        $count = $results['count'];
118
        unset($results['count']);
119
120
        $leads = $results['results'];
121
        unset($results);
122
123
        if ($count && $count < ($start + 1)) {
124
            //the number of entities are now less then the current page so redirect to the last page
125
            if (1 === $count) {
126
                $lastPage = 1;
127
            } else {
128
                $lastPage = (ceil($count / $limit)) ?: 1;
129
            }
130
            $session->set('mautic.lead.page', $lastPage);
131
            $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $lastPage]);
132
133
            return $this->postActionRedirect(
134
                [
135
                    'returnUrl'       => $returnUrl,
136
                    'viewParameters'  => ['page' => $lastPage],
137
                    'contentTemplate' => 'MauticLeadBundle:Lead:index',
138
                    'passthroughVars' => [
139
                        'activeLink'    => '#mautic_contact_index',
140
                        'mauticContent' => 'lead',
141
                    ],
142
                ]
143
            );
144
        }
145
146
        //set what page currently on so that we can return here after form submission/cancellation
147
        $session->set('mautic.lead.page', $page);
148
149
        $tmpl = $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index';
150
151
        $listArgs = [];
152
        if (!$this->get('mautic.security')->isGranted('lead:lists:viewother')) {
153
            $listArgs['filter']['force'] = " $mine";
154
        }
155
156
        $lists = $this->getModel('lead.list')->getUserLists();
157
158
        //check to see if in a single list
159
        $inSingleList = (1 === substr_count($search, "$listCommand:")) ? true : false;
160
        $list         = [];
161
        if ($inSingleList) {
162
            preg_match("/$listCommand:(.*?)(?=\s|$)/", $search, $matches);
163
164
            if (!empty($matches[1])) {
165
                $alias = $matches[1];
166
                foreach ($lists as $l) {
167
                    if ($alias === $l['alias']) {
168
                        $list = $l;
169
                        break;
170
                    }
171
                }
172
            }
173
        }
174
175
        // Get the max ID of the latest lead added
176
        $maxLeadId = $model->getRepository()->getMaxLeadId();
177
178
        /** @var DoNotContactRepository $dncRepository */
179
        $dncRepository = $this->getModel('lead.dnc')->getDncRepo();
180
181
        return $this->delegateView(
182
            [
183
                'viewParameters' => [
184
                    'searchValue'      => $search,
185
                    'columns'          => $this->get('mautic.lead.columns.dictionary')->getColumns(),
186
                    'items'            => $leads,
187
                    'page'             => $page,
188
                    'totalItems'       => $count,
189
                    'limit'            => $limit,
190
                    'permissions'      => $permissions,
191
                    'tmpl'             => $tmpl,
192
                    'indexMode'        => $indexMode,
193
                    'lists'            => $lists,
194
                    'currentList'      => $list,
195
                    'security'         => $this->get('mautic.security'),
196
                    'inSingleList'     => $inSingleList,
197
                    'noContactList'    => $dncRepository->getChannelList(null, array_keys($leads)),
198
                    'maxLeadId'        => $maxLeadId,
199
                    'anonymousShowing' => $anonymousShowing,
200
                ],
201
                'contentTemplate' => "MauticLeadBundle:Lead:{$indexMode}.html.php",
202
                'passthroughVars' => [
203
                    'activeLink'    => '#mautic_contact_index',
204
                    'mauticContent' => 'lead',
205
                    'route'         => $this->generateUrl('mautic_contact_index', ['page' => $page]),
206
                ],
207
            ]
208
        );
209
    }
210
211
    /**
212
     * @return JsonResponse|Response
213
     */
214
    public function quickAddAction()
215
    {
216
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
217
        $model = $this->getModel('lead.lead');
218
219
        // Get the quick add form
220
        $action = $this->generateUrl('mautic_contact_action', ['objectAction' => 'new', 'qf' => 1]);
221
222
        $fields = $this->getModel('lead.field')->getEntities(
223
            [
224
                'filter' => [
225
                    'force' => [
226
                        [
227
                            'column' => 'f.isPublished',
228
                            'expr'   => 'eq',
229
                            'value'  => true,
230
                        ],
231
                        [
232
                            'column' => 'f.isShortVisible',
233
                            'expr'   => 'eq',
234
                            'value'  => true,
235
                        ],
236
                        [
237
                            'column' => 'f.object',
238
                            'expr'   => 'like',
239
                            'value'  => 'lead',
240
                        ],
241
                    ],
242
                ],
243
                'hydration_mode' => 'HYDRATE_ARRAY',
244
            ]
245
        );
246
247
        $quickForm = $model->createForm($model->getEntity(), $this->get('form.factory'), $action, ['fields' => $fields, 'isShortForm' => true]);
248
249
        //set the default owner to the currently logged in user
250
        $currentUser = $this->get('security.token_storage')->getToken()->getUser();
251
        $quickForm->get('owner')->setData($currentUser);
252
253
        return $this->delegateView(
254
            [
255
                'viewParameters' => [
256
                    'quickForm' => $quickForm->createView(),
257
                ],
258
                'contentTemplate' => 'MauticLeadBundle:Lead:quickadd.html.php',
259
                'passthroughVars' => [
260
                    'activeLink'    => '#mautic_contact_index',
261
                    'mauticContent' => 'lead',
262
                    'route'         => false,
263
                ],
264
            ]
265
        );
266
    }
267
268
    /**
269
     * Loads a specific lead into the detailed panel.
270
     *
271
     * @param $objectId
272
     *
273
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
274
     */
275
    public function viewAction($objectId)
276
    {
277
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
278
        $model = $this->getModel('lead.lead');
279
280
        // When we change company data these changes get cached
281
        // so we need to clear the entity manager
282
        $model->getRepository()->clear();
283
284
        /** @var \Mautic\LeadBundle\Entity\Lead $lead */
285
        $lead = $model->getEntity($objectId);
286
287
        //set some permissions
288
        $permissions = $this->get('mautic.security')->isGranted(
289
            [
290
                'lead:leads:viewown',
291
                'lead:leads:viewother',
292
                'lead:leads:create',
293
                'lead:leads:editown',
294
                'lead:leads:editother',
295
                'lead:leads:deleteown',
296
                'lead:leads:deleteother',
297
            ],
298
            'RETURN_ARRAY'
299
        );
300
301
        if (null === $lead) {
302
            //get the page we came from
303
            $page = $this->get('session')->get('mautic.lead.page', 1);
304
305
            //set the return URL
306
            $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $page]);
307
308
            return $this->postActionRedirect(
309
                [
310
                    'returnUrl'       => $returnUrl,
311
                    'viewParameters'  => ['page' => $page],
312
                    'contentTemplate' => 'MauticLeadBundle:Lead:index',
313
                    'passthroughVars' => [
314
                        'activeLink'    => '#mautic_contact_index',
315
                        'mauticContent' => 'contact',
316
                    ],
317
                    'flashes' => [
318
                        [
319
                            'type'    => 'error',
320
                            'msg'     => 'mautic.lead.lead.error.notfound',
321
                            'msgVars' => ['%id%' => $objectId],
322
                        ],
323
                    ],
324
                ]
325
            );
326
        }
327
328
        if (!$this->get('mautic.security')->hasEntityAccess(
329
            'lead:leads:viewown',
330
            'lead:leads:viewother',
331
            $lead->getPermissionUser()
332
        )
333
        ) {
334
            return $this->accessDenied();
335
        }
336
337
        $fields            = $lead->getFields();
338
        $integrationHelper = $this->get('mautic.helper.integration');
339
        $socialProfiles    = (array) $integrationHelper->getUserProfiles($lead, $fields);
340
        $socialProfileUrls = $integrationHelper->getSocialProfileUrlRegex(false);
341
        /* @var \Mautic\LeadBundle\Model\CompanyModel $model */
342
343
        $companyModel = $this->getModel('lead.company');
344
345
        $companiesRepo = $companyModel->getRepository();
346
        $companies     = $companiesRepo->getCompaniesByLeadId($objectId);
347
        // Set the social profile templates
348
        if ($socialProfiles) {
349
            foreach ($socialProfiles as $integration => &$details) {
350
                if ($integrationObject = $integrationHelper->getIntegrationObject($integration)) {
351
                    if ($template = $integrationObject->getSocialProfileTemplate()) {
352
                        $details['social_profile_template'] = $template;
353
                    }
354
                }
355
356
                if (!isset($details['social_profile_template'])) {
357
                    // No profile template found
358
                    unset($socialProfiles[$integration]);
359
                }
360
            }
361
        }
362
363
        // We need the DoNotContact repository to check if a lead is flagged as do not contact
364
        $dnc = $this->getDoctrine()->getManager()->getRepository('MauticLeadBundle:DoNotContact')->getEntriesByLeadAndChannel($lead, 'email');
365
366
        $dncSms = $this->getDoctrine()->getManager()->getRepository('MauticLeadBundle:DoNotContact')->getEntriesByLeadAndChannel($lead, 'sms');
367
368
        $integrationRepo = $this->get('doctrine.orm.entity_manager')->getRepository('MauticPluginBundle:IntegrationEntity');
369
370
        return $this->delegateView(
371
            [
372
                'viewParameters' => [
373
                    'lead'              => $lead,
374
                    'avatarPanelState'  => $this->request->cookies->get('mautic_lead_avatar_panel', 'expanded'),
375
                    'fields'            => $fields,
376
                    'companies'         => $companies,
377
                    'socialProfiles'    => $socialProfiles,
378
                    'socialProfileUrls' => $socialProfileUrls,
379
                    'places'            => $this->getPlaces($lead),
380
                    'permissions'       => $permissions,
381
                    'events'            => $this->getEngagements($lead),
382
                    'upcomingEvents'    => $this->getScheduledCampaignEvents($lead),
383
                    'engagementData'    => $this->getEngagementData($lead),
384
                    'noteCount'         => $this->getModel('lead.note')->getNoteCount($lead, true),
385
                    'integrations'      => $integrationRepo->getIntegrationEntityByLead($lead->getId()),
386
                    'devices'           => $this->get('mautic.lead.repository.lead_device')->getLeadDevices($lead),
387
                    'auditlog'          => $this->getAuditlogs($lead),
388
                    'doNotContact'      => end($dnc),
389
                    'doNotContactSms'   => end($dncSms),
390
                    'leadNotes'         => $this->forward(
391
                        'MauticLeadBundle:Note:index',
392
                        [
393
                            'leadId'     => $lead->getId(),
394
                            'ignoreAjax' => 1,
395
                        ]
396
                    )->getContent(),
397
                ],
398
                'contentTemplate' => 'MauticLeadBundle:Lead:lead.html.php',
399
                'passthroughVars' => [
400
                    'activeLink'    => '#mautic_contact_index',
401
                    'mauticContent' => 'lead',
402
                    'route'         => $this->generateUrl(
403
                        'mautic_contact_action',
404
                        [
405
                            'objectAction' => 'view',
406
                            'objectId'     => $lead->getId(),
407
                        ]
408
                    ),
409
                ],
410
            ]
411
        );
412
    }
413
414
    /**
415
     * Generates new form and processes post data.
416
     *
417
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
418
     */
419
    public function newAction()
420
    {
421
        /** @var LeadModel $model */
422
        $model = $this->getModel('lead.lead');
423
        $lead  = $model->getEntity();
424
425
        if (!$this->get('mautic.security')->isGranted('lead:leads:create')) {
426
            return $this->accessDenied();
427
        }
428
429
        //set the page we came from
430
        $page   = $this->get('session')->get('mautic.lead.page', 1);
431
        $action = $this->generateUrl('mautic_contact_action', ['objectAction' => 'new']);
432
        $fields = $this->getModel('lead.field')->getPublishedFieldArrays('lead');
433
        $form   = $model->createForm($lead, $this->get('form.factory'), $action, ['fields' => $fields]);
434
435
        ///Check for a submitted form and process it
436
        if ('POST' === $this->request->getMethod()) {
437
            $valid = false;
438
            if (!$cancelled = $this->isFormCancelled($form)) {
439
                if ($valid = $this->isFormValid($form)) {
440
                    //get custom field values
441
                    $data = $this->request->request->get('lead');
442
443
                    //pull the data from the form in order to apply the form's formatting
444
                    foreach ($form as $f) {
445
                        if ('companies' !== $f->getName()) {
446
                            $data[$f->getName()] = $f->getData();
447
                        }
448
                    }
449
450
                    $companies = [];
451
                    if (isset($data['companies'])) {
452
                        $companies = $data['companies'];
453
                        unset($data['companies']);
454
                    }
455
456
                    $model->setFieldValues($lead, $data, true);
457
458
                    //form is valid so process the data
459
                    $lead->setManipulator(new LeadManipulator(
460
                        'lead',
461
                        'lead',
462
                        null,
463
                        $this->get('mautic.helper.user')->getUser()->getName()
464
                    ));
465
466
                    /** @var LeadRepository $contactRepository */
467
                    $contactRepository = $this->getDoctrine()->getManager()->getRepository(Lead::class);
468
469
                    // Save here as we need the entity with an ID for the company code bellow.
470
                    $contactRepository->saveEntity($lead);
471
472
                    if (!empty($companies)) {
473
                        $model->modifyCompanies($lead, $companies);
474
                    }
475
476
                    // Save here through the model to trigger all subscribers.
477
                    $model->saveEntity($lead);
478
479
                    // Upload avatar if applicable
480
                    $image = $form['preferred_profile_image']->getData();
481
                    if ('custom' === $image) {
482
                        // Check for a file
483
                        if ($form['custom_avatar']->getData()) {
484
                            $this->uploadAvatar($lead);
485
                        }
486
                    }
487
488
                    $identifier = $this->get('translator')->trans($lead->getPrimaryIdentifier());
489
490
                    $this->addFlash(
491
                        'mautic.core.notice.created',
492
                        [
493
                            '%name%'      => $identifier,
494
                            '%menu_link%' => 'mautic_contact_index',
495
                            '%url%'       => $this->generateUrl(
496
                                'mautic_contact_action',
497
                                [
498
                                    'objectAction' => 'edit',
499
                                    'objectId'     => $lead->getId(),
500
                                ]
501
                            ),
502
                        ]
503
                    );
504
505
                    $inQuickForm = $this->request->get('qf', false);
506
507
                    if ($inQuickForm) {
508
                        $viewParameters = ['page' => $page];
509
                        $returnUrl      = $this->generateUrl('mautic_contact_index', $viewParameters);
510
                        $template       = 'MauticLeadBundle:Lead:index';
511
                    } elseif ($form->get('buttons')->get('save')->isClicked()) {
512
                        $viewParameters = [
513
                            'objectAction' => 'view',
514
                            'objectId'     => $lead->getId(),
515
                        ];
516
                        $returnUrl = $this->generateUrl('mautic_contact_action', $viewParameters);
517
                        $template  = 'MauticLeadBundle:Lead:view';
518
                    } else {
519
                        return $this->editAction($lead->getId(), true);
520
                    }
521
                }
522
            } else {
523
                $viewParameters = ['page' => $page];
524
                $returnUrl      = $this->generateUrl('mautic_contact_index', $viewParameters);
525
                $template       = 'MauticLeadBundle:Lead:index';
526
            }
527
528
            if ($cancelled || $valid) { //cancelled or success
529
                return $this->postActionRedirect(
530
                    [
531
                        'returnUrl'       => $returnUrl,
532
                        'viewParameters'  => $viewParameters,
533
                        'contentTemplate' => $template,
534
                        'passthroughVars' => [
535
                            'activeLink'    => '#mautic_contact_index',
536
                            'mauticContent' => 'lead',
537
                            'closeModal'    => 1, //just in case in quick form
538
                        ],
539
                    ]
540
                );
541
            }
542
        } else {
543
            //set the default owner to the currently logged in user
544
            $currentUser = $this->get('security.token_storage')->getToken()->getUser();
545
            $form->get('owner')->setData($currentUser);
546
        }
547
548
        return $this->delegateView(
549
            [
550
                'viewParameters' => [
551
                    'form'   => $form->createView(),
552
                    'lead'   => $lead,
553
                    'fields' => $model->organizeFieldsByGroup($fields),
554
                ],
555
                'contentTemplate' => 'MauticLeadBundle:Lead:form.html.php',
556
                'passthroughVars' => [
557
                    'activeLink'    => '#mautic_contact_index',
558
                    'mauticContent' => 'lead',
559
                    'route'         => $this->generateUrl(
560
                        'mautic_contact_action',
561
                        [
562
                            'objectAction' => 'new',
563
                        ]
564
                    ),
565
                ],
566
            ]
567
        );
568
    }
569
570
    /**
571
     * Generates edit form.
572
     *
573
     * @param            $objectId
574
     * @param bool|false $ignorePost
575
     *
576
     * @return array|JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
577
     */
578
    public function editAction($objectId, $ignorePost = false)
579
    {
580
        /** @var LeadModel $model */
581
        $model = $this->getModel('lead.lead');
582
        $lead  = $model->getEntity($objectId);
583
584
        //set the page we came from
585
        $page = $this->get('session')->get('mautic.lead.page', 1);
586
587
        //set the return URL
588
        $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $page]);
589
590
        $postActionVars = [
591
            'returnUrl'       => $returnUrl,
592
            'viewParameters'  => ['page' => $page],
593
            'contentTemplate' => 'MauticLeadBundle:Lead:index',
594
            'passthroughVars' => [
595
                'activeLink'    => '#mautic_contact_index',
596
                'mauticContent' => 'lead',
597
            ],
598
        ];
599
        //lead not found
600
        if (null === $lead) {
601
            return $this->postActionRedirect(
602
                array_merge(
603
                    $postActionVars,
604
                    [
605
                        'flashes' => [
606
                            [
607
                                'type'    => 'error',
608
                                'msg'     => 'mautic.lead.lead.error.notfound',
609
                                'msgVars' => ['%id%' => $objectId],
610
                            ],
611
                        ],
612
                    ]
613
                )
614
            );
615
        } elseif (!$this->get('mautic.security')->hasEntityAccess(
616
            'lead:leads:editown',
617
            'lead:leads:editother',
618
            $lead->getPermissionUser()
619
        )
620
        ) {
621
            return $this->accessDenied();
622
        } elseif ($model->isLocked($lead)) {
623
            //deny access if the entity is locked
624
            return $this->isLocked($postActionVars, $lead, 'lead.lead');
625
        }
626
627
        $action = $this->generateUrl('mautic_contact_action', ['objectAction' => 'edit', 'objectId' => $objectId]);
628
        $fields = $this->getModel('lead.field')->getPublishedFieldArrays('lead');
629
        $form   = $model->createForm($lead, $this->get('form.factory'), $action, ['fields' => $fields]);
630
631
        ///Check for a submitted form and process it
632
        if (!$ignorePost && 'POST' == $this->request->getMethod()) {
633
            $valid = false;
634
            if (!$cancelled = $this->isFormCancelled($form)) {
635
                if ($valid = $this->isFormValid($form)) {
636
                    $data = $this->request->request->get('lead');
637
638
                    //pull the data from the form in order to apply the form's formatting
639
                    foreach ($form as $f) {
640
                        if (('companies' !== $f->getName()) && ('company' !== $f->getName())) {
641
                            $data[$f->getName()] = $f->getData();
642
                        }
643
                    }
644
645
                    $companies = [];
646
                    if (isset($data['companies'])) {
647
                        $companies = $data['companies'];
648
                        unset($data['companies']);
649
                    }
650
                    $model->setFieldValues($lead, $data, true);
651
652
                    //form is valid so process the data
653
                    $lead->setManipulator(new LeadManipulator(
654
                        'lead',
655
                        'lead',
656
                        $objectId,
657
                        $this->get('mautic.helper.user')->getUser()->getName()
658
                    ));
659
                    $model->saveEntity($lead, $form->get('buttons')->get('save')->isClicked());
660
                    $model->modifyCompanies($lead, $companies);
661
662
                    // Upload avatar if applicable
663
                    $image = $form['preferred_profile_image']->getData();
664
                    if ('custom' == $image) {
665
                        // Check for a file
666
                        /** @var UploadedFile $file */
667
                        if ($file = $form['custom_avatar']->getData()) {
668
                            $this->uploadAvatar($lead);
669
670
                            // Note the avatar update so that it can be forced to update
671
                            $this->get('session')->set('mautic.lead.avatar.updated', true);
672
                        }
673
                    }
674
675
                    $identifier = $this->get('translator')->trans($lead->getPrimaryIdentifier());
676
677
                    $this->addFlash(
678
                        'mautic.core.notice.updated',
679
                        [
680
                            '%name%'      => $identifier,
681
                            '%menu_link%' => 'mautic_contact_index',
682
                            '%url%'       => $this->generateUrl(
683
                                'mautic_contact_action',
684
                                [
685
                                    'objectAction' => 'edit',
686
                                    'objectId'     => $lead->getId(),
687
                                ]
688
                            ),
689
                        ]
690
                    );
691
                }
692
            } else {
693
                //unlock the entity
694
                $model->unlockEntity($lead);
695
            }
696
697
            if ($cancelled || ($valid && $form->get('buttons')->get('save')->isClicked())) {
698
                $viewParameters = [
699
                    'objectAction' => 'view',
700
                    'objectId'     => $lead->getId(),
701
                ];
702
703
                return $this->postActionRedirect(
704
                    array_merge(
705
                        $postActionVars,
706
                        [
707
                            'returnUrl'       => $this->generateUrl('mautic_contact_action', $viewParameters),
708
                            'viewParameters'  => $viewParameters,
709
                            'contentTemplate' => 'MauticLeadBundle:Lead:view',
710
                        ]
711
                    )
712
                );
713
            } elseif ($valid) {
714
                // Refetch and recreate the form in order to populate data manipulated in the entity itself
715
                $lead = $model->getEntity($objectId);
716
                $form = $model->createForm($lead, $this->get('form.factory'), $action, ['fields' => $fields]);
717
            }
718
        } else {
719
            //lock the entity
720
            $model->lockEntity($lead);
721
        }
722
723
        return $this->delegateView(
724
            [
725
                'viewParameters' => [
726
                    'form'   => $form->createView(),
727
                    'lead'   => $lead,
728
                    'fields' => $lead->getFields(), //pass in the lead fields as they are already organized by ['group']['alias']
729
                ],
730
                'contentTemplate' => 'MauticLeadBundle:Lead:form.html.php',
731
                'passthroughVars' => [
732
                    'activeLink'    => '#mautic_contact_index',
733
                    'mauticContent' => 'lead',
734
                    'route'         => $this->generateUrl(
735
                        'mautic_contact_action',
736
                        [
737
                            'objectAction' => 'edit',
738
                            'objectId'     => $lead->getId(),
739
                        ]
740
                    ),
741
                ],
742
            ]
743
        );
744
    }
745
746
    /**
747
     * Upload an asset.
748
     */
749
    private function uploadAvatar(Lead $lead)
750
    {
751
        $leadInformation = $this->request->files->get('lead', []);
752
        $file            = $leadInformation['custom_avatar'] ?? null;
753
        $avatarDir       = $this->get('mautic.helper.template.avatar')->getAvatarPath(true);
754
755
        if (!file_exists($avatarDir)) {
756
            mkdir($avatarDir);
757
        }
758
759
        $file->move($avatarDir, 'avatar'.$lead->getId());
760
761
        //remove the file from request
762
        $this->request->files->remove('lead');
763
    }
764
765
    /**
766
     * Generates merge form and action.
767
     *
768
     * @param $objectId
769
     *
770
     * @return array|JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
771
     */
772
    public function mergeAction($objectId)
773
    {
774
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
775
        $model    = $this->getModel('lead');
776
        $mainLead = $model->getEntity($objectId);
777
        $page     = $this->get('session')->get('mautic.lead.page', 1);
778
779
        //set the return URL
780
        $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $page]);
781
782
        $postActionVars = [
783
            'returnUrl'       => $returnUrl,
784
            'viewParameters'  => ['page' => $page],
785
            'contentTemplate' => 'MauticLeadBundle:Lead:index',
786
            'passthroughVars' => [
787
                'activeLink'    => '#mautic_contact_index',
788
                'mauticContent' => 'lead',
789
            ],
790
        ];
791
792
        if (null === $mainLead) {
793
            return $this->postActionRedirect(
794
                array_merge(
795
                    $postActionVars,
796
                    [
797
                        'flashes' => [
798
                            [
799
                                'type'    => 'error',
800
                                'msg'     => 'mautic.lead.lead.error.notfound',
801
                                'msgVars' => ['%id%' => $objectId],
802
                            ],
803
                        ],
804
                    ]
805
                )
806
            );
807
        }
808
809
        //do some default filtering
810
        $session = $this->get('session');
811
        $search  = $this->request->get('search', $session->get('mautic.lead.merge.filter', ''));
812
        $session->set('mautic.lead.merge.filter', $search);
813
        $leads = [];
814
815
        if (!empty($search)) {
816
            $filter = [
817
                'string' => $search,
818
                'force'  => [
819
                    [
820
                        'column' => 'l.date_identified',
821
                        'expr'   => 'isNotNull',
822
                        'value'  => $mainLead->getId(),
823
                    ],
824
                    [
825
                        'column' => 'l.id',
826
                        'expr'   => 'neq',
827
                        'value'  => $mainLead->getId(),
828
                    ],
829
                ],
830
            ];
831
832
            $leads = $model->getEntities(
833
                [
834
                    'limit'          => 25,
835
                    'filter'         => $filter,
836
                    'orderBy'        => 'l.firstname,l.lastname,l.company,l.email',
837
                    'orderByDir'     => 'ASC',
838
                    'withTotalCount' => false,
839
                ]
840
            );
841
        }
842
843
        $leadChoices = [];
844
        foreach ($leads as $l) {
845
            $leadChoices[$l->getPrimaryIdentifier()] = $l->getId();
846
        }
847
848
        $action = $this->generateUrl('mautic_contact_action', ['objectAction' => 'merge', 'objectId' => $mainLead->getId()]);
849
850
        $form = $this->get('form.factory')->create(
851
            MergeType::class,
852
            [],
853
            [
854
                'action' => $action,
855
                'leads'  => $leadChoices,
856
            ]
857
        );
858
859
        if ('POST' == $this->request->getMethod()) {
860
            $valid = true;
861
            if (!$this->isFormCancelled($form)) {
862
                if ($valid = $this->isFormValid($form)) {
863
                    $data      = $form->getData();
864
                    $secLeadId = $data['lead_to_merge'];
865
                    $secLead   = $model->getEntity($secLeadId);
866
867
                    if (null === $secLead) {
868
                        return $this->postActionRedirect(
869
                            array_merge(
870
                                $postActionVars,
871
                                [
872
                                    'flashes' => [
873
                                        [
874
                                            'type'    => 'error',
875
                                            'msg'     => 'mautic.lead.lead.error.notfound',
876
                                            'msgVars' => ['%id%' => $secLead->getId()],
877
                                        ],
878
                                    ],
879
                                ]
880
                            )
881
                        );
882
                    } elseif (
883
                        !$this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $mainLead->getPermissionUser())
884
                        || !$this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $secLead->getPermissionUser())
885
                    ) {
886
                        return $this->accessDenied();
887
                    } elseif ($model->isLocked($mainLead)) {
888
                        //deny access if the entity is locked
889
                        return $this->isLocked($postActionVars, $secLead, 'lead');
890
                    } elseif ($model->isLocked($secLead)) {
891
                        //deny access if the entity is locked
892
                        return $this->isLocked($postActionVars, $secLead, 'lead');
893
                    }
894
895
                    //Both leads are good so now we merge them
896
                    /** @var ContactMerger $contactMerger */
897
                    $contactMerger = $this->container->get('mautic.lead.merger');
898
                    try {
899
                        $mainLead = $contactMerger->merge($mainLead, $secLead);
900
                    } catch (SameContactException $exception) {
901
                    }
902
                }
903
            }
904
905
            if ($valid) {
906
                $viewParameters = [
907
                    'objectId'     => $mainLead->getId(),
908
                    'objectAction' => 'view',
909
                ];
910
911
                return $this->postActionRedirect(
912
                    [
913
                        'returnUrl'       => $this->generateUrl('mautic_contact_action', $viewParameters),
914
                        'viewParameters'  => $viewParameters,
915
                        'contentTemplate' => 'MauticLeadBundle:Lead:view',
916
                        'passthroughVars' => [
917
                            'closeModal' => 1,
918
                        ],
919
                    ]
920
                );
921
            }
922
        }
923
924
        $tmpl = $this->request->get('tmpl', 'index');
925
926
        return $this->delegateView(
927
            [
928
                'viewParameters' => [
929
                    'tmpl'         => $tmpl,
930
                    'leads'        => $leads,
931
                    'searchValue'  => $search,
932
                    'action'       => $action,
933
                    'form'         => $form->createView(),
934
                    'currentRoute' => $this->generateUrl(
935
                        'mautic_contact_action',
936
                        [
937
                            'objectAction' => 'merge',
938
                            'objectId'     => $mainLead->getId(),
939
                        ]
940
                    ),
941
                ],
942
                'contentTemplate' => 'MauticLeadBundle:Lead:merge.html.php',
943
                'passthroughVars' => [
944
                    'route'  => false,
945
                    'target' => ('update' == $tmpl) ? '.lead-merge-options' : null,
946
                ],
947
            ]
948
        );
949
    }
950
951
    /**
952
     * Generates contact frequency rules form and action.
953
     *
954
     * @param $objectId
955
     *
956
     * @return array|JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
957
     */
958
    public function contactFrequencyAction($objectId)
959
    {
960
        /** @var LeadModel $model */
961
        $model = $this->getModel('lead');
962
        $lead  = $model->getEntity($objectId);
963
964
        if (null === $lead
965
            || !$this->get('mautic.security')->hasEntityAccess(
966
                'lead:leads:editown',
967
                'lead:leads:editother',
968
                $lead->getPermissionUser()
969
            )
970
        ) {
971
            return $this->accessDenied();
972
        }
973
974
        $viewParameters = [
975
            'objectId'     => $lead->getId(),
976
            'objectAction' => 'view',
977
        ];
978
979
        $form = $this->getFrequencyRuleForm(
980
            $lead,
981
            $viewParameters,
982
            $data,
983
            false,
984
            $this->generateUrl('mautic_contact_action', ['objectAction' => 'contactFrequency', 'objectId' => $lead->getId()])
985
        );
986
987
        if (true === $form) {
988
            return $this->postActionRedirect(
989
                [
990
                    'returnUrl' => $this->generateUrl('mautic_contact_action', [
991
                        'objectId'     => $lead->getId(),
992
                        'objectAction' => 'view',
993
                    ]),
994
                    'viewParameters'  => $viewParameters,
995
                    'contentTemplate' => 'MauticLeadBundle:Lead:view',
996
                    'passthroughVars' => [
997
                        'closeModal' => 1,
998
                    ],
999
                ]
1000
            );
1001
        }
1002
1003
        $tmpl = $this->request->get('tmpl', 'index');
1004
1005
        return $this->delegateView(
1006
            [
1007
                'viewParameters' => array_merge(
1008
                    [
1009
                        'tmpl'         => $tmpl,
1010
                        'form'         => $form->createView(),
1011
                        'currentRoute' => $this->generateUrl(
1012
                            'mautic_contact_action',
1013
                            [
1014
                                'objectAction' => 'contactFrequency',
1015
                                'objectId'     => $lead->getId(),
1016
                            ]
1017
                        ),
1018
                        'lead' => $lead,
1019
                    ],
1020
                    $viewParameters
1021
                ),
1022
                'contentTemplate' => 'MauticLeadBundle:Lead:frequency.html.php',
1023
                'passthroughVars' => [
1024
                    'route'  => false,
1025
                    'target' => ('update' == $tmpl) ? '.lead-frequency-options' : null,
1026
                ],
1027
            ]
1028
        );
1029
    }
1030
1031
    /**
1032
     * Deletes the entity.
1033
     *
1034
     * @param $objectId
1035
     *
1036
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
1037
     */
1038
    public function deleteAction($objectId)
1039
    {
1040
        $page      = $this->get('session')->get('mautic.lead.page', 1);
1041
        $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $page]);
1042
        $flashes   = [];
1043
1044
        $postActionVars = [
1045
            'returnUrl'       => $returnUrl,
1046
            'viewParameters'  => ['page' => $page],
1047
            'contentTemplate' => 'MauticLeadBundle:Lead:index',
1048
            'passthroughVars' => [
1049
                'activeLink'    => '#mautic_contact_index',
1050
                'mauticContent' => 'lead',
1051
            ],
1052
        ];
1053
1054
        if ('POST' == $this->request->getMethod()) {
1055
            $model  = $this->getModel('lead.lead');
1056
            $entity = $model->getEntity($objectId);
1057
1058
            if (null === $entity) {
1059
                $flashes[] = [
1060
                    'type'    => 'error',
1061
                    'msg'     => 'mautic.lead.lead.error.notfound',
1062
                    'msgVars' => ['%id%' => $objectId],
1063
                ];
1064
            } elseif (!$this->get('mautic.security')->hasEntityAccess(
1065
                'lead:leads:deleteown',
1066
                'lead:leads:deleteother',
1067
                $entity->getPermissionUser()
1068
            )
1069
            ) {
1070
                return $this->accessDenied();
1071
            } elseif ($model->isLocked($entity)) {
1072
                return $this->isLocked($postActionVars, $entity, 'lead.lead');
1073
            } else {
1074
                $model->deleteEntity($entity);
1075
1076
                $identifier = $this->get('translator')->trans($entity->getPrimaryIdentifier());
1077
                $flashes[]  = [
1078
                    'type'    => 'notice',
1079
                    'msg'     => 'mautic.core.notice.deleted',
1080
                    'msgVars' => [
1081
                        '%name%' => $identifier,
1082
                        '%id%'   => $objectId,
1083
                    ],
1084
                ];
1085
            }
1086
        } //else don't do anything
1087
1088
        return $this->postActionRedirect(
1089
            array_merge(
1090
                $postActionVars,
1091
                [
1092
                    'flashes' => $flashes,
1093
                ]
1094
            )
1095
        );
1096
    }
1097
1098
    /**
1099
     * Deletes a group of entities.
1100
     *
1101
     * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
1102
     */
1103
    public function batchDeleteAction()
1104
    {
1105
        $page      = $this->get('session')->get('mautic.lead.page', 1);
1106
        $returnUrl = $this->generateUrl('mautic_contact_index', ['page' => $page]);
1107
        $flashes   = [];
1108
1109
        $postActionVars = [
1110
            'returnUrl'       => $returnUrl,
1111
            'viewParameters'  => ['page' => $page],
1112
            'contentTemplate' => 'MauticLeadBundle:Lead:index',
1113
            'passthroughVars' => [
1114
                'activeLink'    => '#mautic_contact_index',
1115
                'mauticContent' => 'lead',
1116
            ],
1117
        ];
1118
1119
        if ('POST' == $this->request->getMethod()) {
1120
            $model     = $this->getModel('lead');
1121
            $ids       = json_decode($this->request->query->get('ids', '{}'));
1122
            $deleteIds = [];
1123
1124
            // Loop over the IDs to perform access checks pre-delete
1125
            foreach ($ids as $objectId) {
1126
                $entity = $model->getEntity($objectId);
1127
1128
                if (null === $entity) {
1129
                    $flashes[] = [
1130
                        'type'    => 'error',
1131
                        'msg'     => 'mautic.lead.lead.error.notfound',
1132
                        'msgVars' => ['%id%' => $objectId],
1133
                    ];
1134
                } elseif (!$this->get('mautic.security')->hasEntityAccess(
1135
                    'lead:leads:deleteown',
1136
                    'lead:leads:deleteother',
1137
                    $entity->getPermissionUser()
1138
                )
1139
                ) {
1140
                    $flashes[] = $this->accessDenied(true);
1141
                } elseif ($model->isLocked($entity)) {
1142
                    $flashes[] = $this->isLocked($postActionVars, $entity, 'lead', true);
1143
                } else {
1144
                    $deleteIds[] = $objectId;
1145
                }
1146
            }
1147
1148
            // Delete everything we are able to
1149
            if (!empty($deleteIds)) {
1150
                $entities = $model->deleteEntities($deleteIds);
1151
1152
                $flashes[] = [
1153
                    'type'    => 'notice',
1154
                    'msg'     => 'mautic.lead.lead.notice.batch_deleted',
1155
                    'msgVars' => [
1156
                        '%count%' => count($entities),
1157
                    ],
1158
                ];
1159
            }
1160
        } //else don't do anything
1161
1162
        return $this->postActionRedirect(
1163
            array_merge(
1164
                $postActionVars,
1165
                [
1166
                    'flashes' => $flashes,
1167
                ]
1168
            )
1169
        );
1170
    }
1171
1172
    /**
1173
     * Add/remove lead from a list.
1174
     *
1175
     * @param $objectId
1176
     *
1177
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1178
     */
1179
    public function listAction($objectId)
1180
    {
1181
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1182
        $model = $this->getModel('lead');
1183
        $lead  = $model->getEntity($objectId);
1184
1185
        if (null != $lead
1186
            && $this->get('mautic.security')->hasEntityAccess(
1187
                'lead:leads:editown',
1188
                'lead:leads:editother',
1189
                $lead->getPermissionUser()
1190
            )
1191
        ) {
1192
            /** @var \Mautic\LeadBundle\Model\ListModel $listModel */
1193
            $listModel = $this->getModel('lead.list');
1194
            $lists     = $listModel->getUserLists();
1195
1196
            // Get a list of lists for the lead
1197
            $leadsLists = $model->getLists($lead, true, true);
1198
        } else {
1199
            $lists = $leadsLists = [];
1200
        }
1201
1202
        return $this->delegateView(
1203
            [
1204
                'viewParameters' => [
1205
                    'lists'      => $lists,
1206
                    'leadsLists' => $leadsLists,
1207
                    'lead'       => $lead,
1208
                ],
1209
                'contentTemplate' => 'MauticLeadBundle:LeadLists:index.html.php',
1210
            ]
1211
        );
1212
    }
1213
1214
    /**
1215
     * Add/remove lead from a company.
1216
     *
1217
     * @param $objectId
1218
     *
1219
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1220
     */
1221
    public function companyAction($objectId)
1222
    {
1223
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1224
        $model = $this->getModel('lead');
1225
        $lead  = $model->getEntity($objectId);
1226
1227
        if (null != $lead
1228
            && $this->get('mautic.security')->hasEntityAccess(
1229
                'lead:leads:editown',
1230
                'lead:leads:editother',
1231
                $lead->getOwner()
1232
            )
1233
        ) {
1234
            /** @var \Mautic\LeadBundle\Model\CompanyModel $companyModel */
1235
            $companyModel = $this->getModel('lead.company');
1236
            $companies    = $companyModel->getUserCompanies();
1237
1238
            // Get a list of lists for the lead
1239
            $companyLeads = $lead->getCompanies();
1240
            foreach ($companyLeads as $cl) {
1241
                $companyLead[$cl->getId()] = $cl->getId();
1242
            }
1243
        } else {
1244
            $companies = $companyLead = [];
1245
        }
1246
1247
        return $this->delegateView(
1248
            [
1249
                'viewParameters' => [
1250
                    'companies'   => $companies,
1251
                    'companyLead' => $companyLead,
1252
                    'lead'        => $lead,
1253
                ],
1254
                'contentTemplate' => 'MauticLeadBundle:Lead:company.html.php',
1255
            ]
1256
        );
1257
    }
1258
1259
    /**
1260
     * Add/remove lead from a campaign.
1261
     *
1262
     * @param $objectId
1263
     *
1264
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1265
     */
1266
    public function campaignAction($objectId)
1267
    {
1268
        $model = $this->getModel('lead');
1269
        $lead  = $model->getEntity($objectId);
1270
1271
        if (null != $lead
1272
            && $this->get('mautic.security')->hasEntityAccess(
1273
                'lead:leads:editown',
1274
                'lead:leads:editother',
1275
                $lead->getPermissionUser()
1276
            )
1277
        ) {
1278
            /** @var \Mautic\CampaignBundle\Model\CampaignModel $campaignModel */
1279
            $campaignModel  = $this->getModel('campaign');
1280
            $campaigns      = $campaignModel->getPublishedCampaigns(true);
1281
            $leadsCampaigns = $campaignModel->getLeadCampaigns($lead, true);
1282
1283
            foreach ($campaigns as $c) {
1284
                $campaigns[$c['id']]['inCampaign'] = (isset($leadsCampaigns[$c['id']])) ? true : false;
1285
            }
1286
        } else {
1287
            $campaigns = [];
1288
        }
1289
1290
        return $this->delegateView(
1291
            [
1292
                'viewParameters' => [
1293
                    'campaigns' => $campaigns,
1294
                    'lead'      => $lead,
1295
                ],
1296
                'contentTemplate' => 'MauticLeadBundle:LeadCampaigns:index.html.php',
1297
            ]
1298
        );
1299
    }
1300
1301
    /**
1302
     * @param int $objectId
1303
     *
1304
     * @return JsonResponse
1305
     */
1306
    public function emailAction($objectId = 0)
1307
    {
1308
        $valid = $cancelled = false;
1309
1310
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1311
        $model = $this->getModel('lead');
1312
1313
        /** @var \Mautic\LeadBundle\Entity\Lead $lead */
1314
        $lead = $model->getEntity($objectId);
1315
1316
        if (null === $lead
1317
            || !$this->get('mautic.security')->hasEntityAccess(
1318
                'lead:leads:viewown',
1319
                'lead:leads:viewother',
1320
                $lead->getPermissionUser()
1321
            )
1322
        ) {
1323
            return $this->modalAccessDenied();
1324
        }
1325
1326
        $leadFields       = $lead->getProfileFields();
1327
        $leadFields['id'] = $lead->getId();
1328
        $leadEmail        = $leadFields['email'];
1329
        $leadName         = $leadFields['firstname'].' '.$leadFields['lastname'];
1330
        $mailerIsOwner    = $this->get('mautic.helper.core_parameters')->getParameter('mailer_is_owner');
1331
1332
        // Set onwer ID to be the current user ID so it will use his signature
1333
        $leadFields['owner_id'] = $this->get('mautic.helper.user')->getUser()->getId();
1334
1335
        $inList = ('GET' == $this->request->getMethod())
1336
            ? $this->request->get('list', 0)
1337
            : $this->request->request->get(
1338
                'lead_quickemail[list]',
1339
                0,
1340
                true
1341
            );
1342
        $email = ['list' => $inList];
1343
1344
        // Try set owner If should be mailer
1345
        if ($lead->getOwner()) {
1346
            $leadFields['owner_id'] = $lead->getOwner()->getId();
1347
            if ($mailerIsOwner) {
1348
                $email['fromname'] = sprintf(
1349
                    '%s %s',
1350
                    $lead->getOwner()->getFirstName(),
1351
                    $lead->getOwner()->getLastName()
1352
                );
1353
                $email['from'] = $lead->getOwner()->getEmail();
1354
            }
1355
        }
1356
1357
        // Check if lead has a bounce status
1358
        $dnc    = $this->getDoctrine()->getManager()->getRepository('MauticLeadBundle:DoNotContact')->getEntriesByLeadAndChannel($lead, 'email');
1359
        $action = $this->generateUrl('mautic_contact_action', ['objectAction' => 'email', 'objectId' => $objectId]);
1360
        $form   = $this->get('form.factory')->create(EmailType::class, $email, ['action' => $action]);
1361
1362
        if ('POST' == $this->request->getMethod()) {
1363
            $valid = false;
1364
            if (!$cancelled = $this->isFormCancelled($form)) {
1365
                if ($valid = $this->isFormValid($form)) {
1366
                    $email = $form->getData();
1367
1368
                    $bodyCheck = trim(strip_tags($email['body']));
1369
                    if (!empty($bodyCheck)) {
1370
                        $mailer = $this->get('mautic.helper.mailer')->getMailer();
1371
1372
                        // To lead
1373
                        $mailer->addTo($leadEmail, $leadName);
1374
1375
                        // From user
1376
                        $user = $this->get('mautic.helper.user')->getUser();
1377
1378
                        $mailer->setFrom(
1379
                            $email['from'],
1380
                            empty($email['fromname']) ? null : $email['fromname']
1381
                        );
1382
1383
                        // Set Content
1384
                        $mailer->setBody($email['body']);
1385
                        $mailer->parsePlainText($email['body']);
1386
1387
                        // Set lead
1388
                        $mailer->setLead($leadFields);
1389
                        $mailer->setIdHash();
1390
1391
                        $mailer->setSubject($email['subject']);
1392
1393
                        // Ensure safe emoji for notification
1394
                        $subject = EmojiHelper::toHtml($email['subject']);
1395
                        if ($mailer->send(true, false, false)) {
1396
                            $mailer->createEmailStat();
1397
                            $this->addFlash(
1398
                                'mautic.lead.email.notice.sent',
1399
                                [
1400
                                    '%subject%' => $subject,
1401
                                    '%email%'   => $leadEmail,
1402
                                ]
1403
                            );
1404
                        } else {
1405
                            $errors = $mailer->getErrors();
1406
1407
                            // Unset the array of failed email addresses
1408
                            if (isset($errors['failures'])) {
1409
                                unset($errors['failures']);
1410
                            }
1411
1412
                            $form->addError(
1413
                                new FormError(
1414
                                    $this->get('translator')->trans(
1415
                                        'mautic.lead.email.error.failed',
1416
                                        [
1417
                                            '%subject%' => $subject,
1418
                                            '%email%'   => $leadEmail,
1419
                                            '%error%'   => (is_array($errors)) ? implode('<br />', $errors) : $errors,
1420
                                        ],
1421
                                        'flashes'
1422
                                    )
1423
                                )
1424
                            );
1425
                            $valid = false;
1426
                        }
1427
                    } else {
1428
                        $form['body']->addError(
1429
                            new FormError(
1430
                                $this->get('translator')->trans('mautic.lead.email.body.required', [], 'validators')
1431
                            )
1432
                        );
1433
                        $valid = false;
1434
                    }
1435
                }
1436
            }
1437
        }
1438
1439
        if (empty($leadEmail) || $valid || $cancelled) {
1440
            if ($inList) {
1441
                $route          = 'mautic_contact_index';
1442
                $viewParameters = [
1443
                    'page' => $this->get('session')->get('mautic.lead.page', 1),
1444
                ];
1445
                $func = 'index';
1446
            } else {
1447
                $route          = 'mautic_contact_action';
1448
                $viewParameters = [
1449
                    'objectAction' => 'view',
1450
                    'objectId'     => $objectId,
1451
                ];
1452
                $func = 'view';
1453
            }
1454
1455
            return $this->postActionRedirect(
1456
                [
1457
                    'returnUrl'       => $this->generateUrl($route, $viewParameters),
1458
                    'viewParameters'  => $viewParameters,
1459
                    'contentTemplate' => 'MauticLeadBundle:Lead:'.$func,
1460
                    'passthroughVars' => [
1461
                        'mauticContent' => 'lead',
1462
                        'closeModal'    => 1,
1463
                    ],
1464
                ]
1465
            );
1466
        }
1467
1468
        return $this->ajaxAction(
1469
            [
1470
                'contentTemplate' => 'MauticLeadBundle:Lead:email.html.php',
1471
                'viewParameters'  => [
1472
                    'form' => $form->createView(),
1473
                    'dnc'  => end($dnc),
1474
                ],
1475
                'passthroughVars' => [
1476
                    'mauticContent' => 'leadEmail',
1477
                    'route'         => false,
1478
                ],
1479
            ]
1480
        );
1481
    }
1482
1483
    /**
1484
     * Bulk edit lead campaigns.
1485
     *
1486
     * @param int $objectId
1487
     *
1488
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1489
     */
1490
    public function batchCampaignsAction($objectId = 0)
1491
    {
1492
        /** @var \Mautic\CampaignBundle\Model\CampaignModel $campaignModel */
1493
        $campaignModel = $this->getModel('campaign');
1494
1495
        if ('POST' == $this->request->getMethod()) {
1496
            /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1497
            $model = $this->getModel('lead');
1498
            $data  = $this->request->request->get('lead_batch', [], true);
1499
            $ids   = json_decode($data['ids'], true);
1500
1501
            $entities = [];
1502
            if (is_array($ids)) {
1503
                $entities = $model->getEntities(
1504
                    [
1505
                        'filter' => [
1506
                            'force' => [
1507
                                [
1508
                                    'column' => 'l.id',
1509
                                    'expr'   => 'in',
1510
                                    'value'  => $ids,
1511
                                ],
1512
                            ],
1513
                        ],
1514
                        'ignore_paginator' => true,
1515
                    ]
1516
                );
1517
            }
1518
1519
            foreach ($entities as $key => $lead) {
1520
                if (!$this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $lead->getPermissionUser())) {
1521
                    unset($entities[$key]);
1522
                }
1523
            }
1524
1525
            $add    = (!empty($data['add'])) ? $data['add'] : [];
1526
            $remove = (!empty($data['remove'])) ? $data['remove'] : [];
1527
1528
            if ($count = count($entities)) {
1529
                $campaigns = $campaignModel->getEntities(
1530
                    [
1531
                        'filter' => [
1532
                            'force' => [
1533
                                [
1534
                                    'column' => 'c.id',
1535
                                    'expr'   => 'in',
1536
                                    'value'  => array_merge($add, $remove),
1537
                                ],
1538
                            ],
1539
                        ],
1540
                        'ignore_paginator' => true,
1541
                    ]
1542
                );
1543
1544
                /** @var \Mautic\CampaignBundle\Membership\MembershipManager $membershipManager */
1545
                $membershipManager = $this->get('mautic.campaign.membership.manager');
1546
1547
                if (!empty($add)) {
1548
                    foreach ($add as $cid) {
1549
                        $membershipManager->addContacts(new ArrayCollection($entities), $campaigns[$cid]);
1550
                    }
1551
                }
1552
1553
                if (!empty($remove)) {
1554
                    foreach ($remove as $cid) {
1555
                        $membershipManager->removeContacts(new ArrayCollection($entities), $campaigns[$cid]);
1556
                    }
1557
                }
1558
            }
1559
1560
            $this->addFlash(
1561
                'mautic.lead.batch_leads_affected',
1562
                [
1563
                    'pluralCount' => $count,
1564
                    '%count%'     => $count,
1565
                ]
1566
            );
1567
1568
            return new JsonResponse(
1569
                [
1570
                    'closeModal' => true,
1571
                    'flashes'    => $this->getFlashContent(),
1572
                ]
1573
            );
1574
        } else {
1575
            // Get a list of campaigns
1576
            $campaigns = $campaignModel->getPublishedCampaigns(true);
1577
            $items     = [];
1578
            foreach ($campaigns as $campaign) {
1579
                $items[$campaign['name']] = $campaign['id'];
1580
            }
1581
1582
            $route = $this->generateUrl(
1583
                'mautic_contact_action',
1584
                [
1585
                    'objectAction' => 'batchCampaigns',
1586
                ]
1587
            );
1588
1589
            return $this->delegateView(
1590
                [
1591
                    'viewParameters' => [
1592
                        'form' => $this->createForm(
1593
                            BatchType::class,
1594
                            [],
1595
                            [
1596
                                'items'  => $items,
1597
                                'action' => $route,
1598
                            ]
1599
                        )->createView(),
1600
                    ],
1601
                    'contentTemplate' => 'MauticLeadBundle:Batch:form.html.php',
1602
                    'passthroughVars' => [
1603
                        'activeLink'    => '#mautic_contact_index',
1604
                        'mauticContent' => 'leadBatch',
1605
                        'route'         => $route,
1606
                    ],
1607
                ]
1608
            );
1609
        }
1610
    }
1611
1612
    /**
1613
     * Bulk add leads to the DNC list.
1614
     *
1615
     * @param int $objectId
1616
     *
1617
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1618
     */
1619
    public function batchDncAction($objectId = 0)
1620
    {
1621
        if ('POST' == $this->request->getMethod()) {
1622
            /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1623
            $model = $this->getModel('lead');
1624
1625
            /** @var \Mautic\LeadBundle\Model\DoNotContact $doNotContact */
1626
            $doNotContact = $this->get('mautic.lead.model.dnc');
1627
1628
            $data = $this->request->request->get('lead_batch_dnc', [], true);
1629
            $ids  = json_decode($data['ids'], true);
1630
1631
            $entities = [];
1632
            if (is_array($ids)) {
1633
                $entities = $model->getEntities(
1634
                    [
1635
                        'filter' => [
1636
                            'force' => [
1637
                                [
1638
                                    'column' => 'l.id',
1639
                                    'expr'   => 'in',
1640
                                    'value'  => $ids,
1641
                                ],
1642
                            ],
1643
                        ],
1644
                        'ignore_paginator' => true,
1645
                    ]
1646
                );
1647
            }
1648
1649
            if ($count = count($entities)) {
1650
                $persistEntities = [];
1651
                foreach ($entities as $lead) {
1652
                    if ($this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $lead->getPermissionUser())) {
1653
                        if ($doNotContact->addDncForContact($lead->getId(), 'email', DoNotContact::MANUAL, $data['reason'])) {
1654
                            $persistEntities[] = $lead;
1655
                        }
1656
                    }
1657
                }
1658
1659
                // Save entities
1660
                $model->saveEntities($persistEntities);
1661
            }
1662
1663
            $this->addFlash(
1664
                'mautic.lead.batch_leads_affected',
1665
                [
1666
                    'pluralCount' => $count,
1667
                    '%count%'     => $count,
1668
                ]
1669
            );
1670
1671
            return new JsonResponse(
1672
                [
1673
                    'closeModal' => true,
1674
                    'flashes'    => $this->getFlashContent(),
1675
                ]
1676
            );
1677
        } else {
1678
            $route = $this->generateUrl(
1679
                'mautic_contact_action',
1680
                [
1681
                    'objectAction' => 'batchDnc',
1682
                ]
1683
            );
1684
1685
            return $this->delegateView(
1686
                [
1687
                    'viewParameters' => [
1688
                        'form' => $this->createForm(
1689
                            DncType::class,
1690
                            [],
1691
                            [
1692
                                'action' => $route,
1693
                            ]
1694
                        )->createView(),
1695
                    ],
1696
                    'contentTemplate' => 'MauticLeadBundle:Batch:form.html.php',
1697
                    'passthroughVars' => [
1698
                        'activeLink'    => '#mautic_contact_index',
1699
                        'mauticContent' => 'leadBatch',
1700
                        'route'         => $route,
1701
                    ],
1702
                ]
1703
            );
1704
        }
1705
    }
1706
1707
    /**
1708
     * Bulk edit lead stages.
1709
     *
1710
     * @param int $objectId
1711
     *
1712
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1713
     */
1714
    public function batchStagesAction($objectId = 0)
1715
    {
1716
        if ('POST' == $this->request->getMethod()) {
1717
            /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1718
            $model = $this->getModel('lead');
1719
            $data  = $this->request->request->get('lead_batch_stage', [], true);
1720
            $ids   = json_decode($data['ids'], true);
1721
1722
            $entities = [];
1723
            if (is_array($ids)) {
1724
                $entities = $model->getEntities(
1725
                    [
1726
                        'filter' => [
1727
                            'force' => [
1728
                                [
1729
                                    'column' => 'l.id',
1730
                                    'expr'   => 'in',
1731
                                    'value'  => $ids,
1732
                                ],
1733
                            ],
1734
                        ],
1735
                        'ignore_paginator' => true,
1736
                    ]
1737
                );
1738
            }
1739
1740
            $count = 0;
1741
            foreach ($entities as $lead) {
1742
                if ($this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $lead->getPermissionUser())) {
1743
                    ++$count;
1744
1745
                    if (!empty($data['addstage'])) {
1746
                        $stageModel = $this->getModel('stage');
1747
1748
                        $stage = $stageModel->getEntity((int) $data['addstage']);
1749
                        $model->addToStages($lead, $stage);
1750
                    }
1751
1752
                    if (!empty($data['removestage'])) {
1753
                        $stage = $stageModel->getEntity($data['removestage']);
1754
                        $model->removeFromStages($lead, $stage);
1755
                    }
1756
                }
1757
            }
1758
            // Save entities
1759
            $model->saveEntities($entities);
1760
            $this->addFlash(
1761
                'mautic.lead.batch_leads_affected',
1762
                [
1763
                    'pluralCount' => $count,
1764
                    '%count%'     => $count,
1765
                ]
1766
            );
1767
1768
            return new JsonResponse(
1769
                [
1770
                    'closeModal' => true,
1771
                    'flashes'    => $this->getFlashContent(),
1772
                ]
1773
            );
1774
        } else {
1775
            // Get a list of lists
1776
            /** @var \Mautic\StageBundle\Model\StageModel $model */
1777
            $model  = $this->getModel('stage');
1778
            $stages = $model->getUserStages();
1779
            $items  = [];
1780
            foreach ($stages as $stage) {
1781
                $items[$stage['name']] = $stage['id'];
1782
            }
1783
1784
            $route = $this->generateUrl(
1785
                'mautic_contact_action',
1786
                [
1787
                    'objectAction' => 'batchStages',
1788
                ]
1789
            );
1790
1791
            return $this->delegateView(
1792
                [
1793
                    'viewParameters' => [
1794
                        'form' => $this->createForm(
1795
                            StageType::class,
1796
                            [],
1797
                            [
1798
                                'items'  => $items,
1799
                                'action' => $route,
1800
                            ]
1801
                        )->createView(),
1802
                    ],
1803
                    'contentTemplate' => 'MauticLeadBundle:Batch:form.html.php',
1804
                    'passthroughVars' => [
1805
                        'activeLink'    => '#mautic_contact_index',
1806
                        'mauticContent' => 'leadBatch',
1807
                        'route'         => $route,
1808
                    ],
1809
                ]
1810
            );
1811
        }
1812
    }
1813
1814
    /**
1815
     * Bulk edit lead owner.
1816
     *
1817
     * @param int $objectId
1818
     *
1819
     * @return JsonResponse|\Symfony\Component\HttpFoundation\Response
1820
     */
1821
    public function batchOwnersAction($objectId = 0)
0 ignored issues
show
The parameter $objectId is not used and could be removed. ( Ignorable by Annotation )

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

1821
    public function batchOwnersAction(/** @scrutinizer ignore-unused */ $objectId = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1822
    {
1823
        if ('POST' == $this->request->getMethod()) {
1824
            /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1825
            $model = $this->getModel('lead');
1826
            $data  = $this->request->request->get('lead_batch_owner', [], true);
0 ignored issues
show
The call to Symfony\Component\HttpFo...ion\ParameterBag::get() has too many arguments starting with true. ( Ignorable by Annotation )

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

1826
            /** @scrutinizer ignore-call */ 
1827
            $data  = $this->request->request->get('lead_batch_owner', [], true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1827
            $ids   = json_decode($data['ids'], true);
1828
1829
            $entities = [];
1830
            if (is_array($ids)) {
1831
                $entities = $model->getEntities(
1832
                    [
1833
                        'filter' => [
1834
                            'force' => [
1835
                                [
1836
                                    'column' => 'l.id',
1837
                                    'expr'   => 'in',
1838
                                    'value'  => $ids,
1839
                                ],
1840
                            ],
1841
                        ],
1842
                        'ignore_paginator' => true,
1843
                    ]
1844
                );
1845
            }
1846
            $count = 0;
1847
            foreach ($entities as $lead) {
1848
                if ($this->get('mautic.security')->hasEntityAccess('lead:leads:editown', 'lead:leads:editother', $lead->getPermissionUser())) {
1849
                    ++$count;
1850
1851
                    if (!empty($data['addowner'])) {
1852
                        $userModel = $this->getModel('user');
1853
                        $user      = $userModel->getEntity((int) $data['addowner']);
1854
                        $lead->setOwner($user);
1855
                    }
1856
                }
1857
            }
1858
            // Save entities
1859
            $model->saveEntities($entities);
1860
            $this->addFlash(
0 ignored issues
show
Deprecated Code introduced by
The function Mautic\CoreBundle\Contro...nController::addFlash() has been deprecated: Will be removed in Mautic 3.0. Use CommonController::flashBag->addFlash() instead. ( Ignorable by Annotation )

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

1860
            /** @scrutinizer ignore-deprecated */ $this->addFlash(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1861
                'mautic.lead.batch_leads_affected',
1862
                [
1863
                    'pluralCount' => $count,
1864
                    '%count%'     => $count,
1865
                ]
1866
            );
1867
1868
            return new JsonResponse(
1869
                [
1870
                    'closeModal' => true,
1871
                    'flashes'    => $this->getFlashContent(),
1872
                ]
1873
            );
1874
        } else {
1875
            $users = $this->getModel('user.user')->getRepository()->getUserList('', 0);
0 ignored issues
show
The method getUserList() 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

1875
            $users = $this->getModel('user.user')->getRepository()->/** @scrutinizer ignore-call */ getUserList('', 0);
Loading history...
1876
            $items = [];
1877
            foreach ($users as $user) {
1878
                $items[$user['firstName'].' '.$user['lastName']] = $user['id'];
1879
            }
1880
1881
            $route = $this->generateUrl(
1882
                'mautic_contact_action',
1883
                [
1884
                    'objectAction' => 'batchOwners',
1885
                ]
1886
            );
1887
1888
            return $this->delegateView(
1889
                [
1890
                    'viewParameters' => [
1891
                        'form' => $this->createForm(
1892
                            OwnerType::class,
1893
                            [],
1894
                            [
1895
                                'items'  => $items,
1896
                                'action' => $route,
1897
                            ]
1898
                        )->createView(),
1899
                    ],
1900
                    'contentTemplate' => 'MauticLeadBundle:Batch:form.html.php',
1901
                    'passthroughVars' => [
1902
                        'activeLink'    => '#mautic_contact_index',
1903
                        'mauticContent' => 'leadBatch',
1904
                        'route'         => $route,
1905
                    ],
1906
                ]
1907
            );
1908
        }
1909
    }
1910
1911
    /**
1912
     * Bulk export contacts.
1913
     *
1914
     * @return array|JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\StreamedResponse
1915
     */
1916
    public function batchExportAction()
1917
    {
1918
        //set some permissions
1919
        $permissions = $this->get('mautic.security')->isGranted(
1920
            [
1921
                'lead:leads:viewown',
1922
                'lead:leads:viewother',
1923
                'lead:leads:create',
1924
                'lead:leads:editown',
1925
                'lead:leads:editother',
1926
                'lead:leads:deleteown',
1927
                'lead:leads:deleteother',
1928
            ],
1929
            'RETURN_ARRAY'
1930
        );
1931
1932
        if (!$permissions['lead:leads:viewown'] && !$permissions['lead:leads:viewother']) {
1933
            return $this->accessDenied();
1934
        }
1935
1936
        /** @var \Mautic\LeadBundle\Model\LeadModel $model */
1937
        $model      = $this->getModel('lead');
1938
        $session    = $this->get('session');
1939
        $search     = $session->get('mautic.lead.filter', '');
1940
        $orderBy    = $session->get('mautic.lead.orderby', 'l.last_active');
1941
        $orderByDir = $session->get('mautic.lead.orderbydir', 'DESC');
1942
        $ids        = $this->request->get('ids');
1943
1944
        $filter     = ['string' => $search, 'force' => ''];
1945
        $translator = $this->get('translator');
1946
        $anonymous  = $translator->trans('mautic.lead.lead.searchcommand.isanonymous');
1947
        $mine       = $translator->trans('mautic.core.searchcommand.ismine');
1948
        $indexMode  = $session->get('mautic.lead.indexmode', 'list');
1949
        $dataType   = $this->request->get('filetype');
1950
1951
        if (!empty($ids)) {
1952
            $filter['force'] = [
1953
                [
1954
                    'column' => 'l.id',
1955
                    'expr'   => 'in',
1956
                    'value'  => json_decode($ids, true),
1957
                ],
1958
            ];
1959
        } else {
1960
            if ('list' != $indexMode || ('list' == $indexMode && false === strpos($search, $anonymous))) {
1961
                //remove anonymous leads unless requested to prevent clutter
1962
                $filter['force'] .= " !$anonymous";
1963
            }
1964
1965
            if (!$permissions['lead:leads:viewother']) {
1966
                $filter['force'] .= " $mine";
1967
            }
1968
        }
1969
1970
        $args = [
1971
            'start'          => 0,
1972
            'limit'          => 200,
1973
            'filter'         => $filter,
1974
            'orderBy'        => $orderBy,
1975
            'orderByDir'     => $orderByDir,
1976
            'withTotalCount' => true,
1977
        ];
1978
1979
        $resultsCallback = function ($contact) {
1980
            return $contact->getProfileFields();
1981
        };
1982
1983
        $iterator = new IteratorExportDataModel($model, $args, $resultsCallback);
1984
1985
        return $this->exportResultsAs($iterator, $dataType, 'contacts');
1986
    }
1987
1988
    /**
1989
     * @param $contactId
1990
     *
1991
     * @return array|JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\StreamedResponse
1992
     */
1993
    public function contactExportAction($contactId)
1994
    {
1995
        //set some permissions
1996
        $permissions = $this->get('mautic.security')->isGranted(
1997
            [
1998
                'lead:leads:viewown',
1999
                'lead:leads:viewother',
2000
            ],
2001
            'RETURN_ARRAY'
2002
        );
2003
2004
        if (!$permissions['lead:leads:viewown'] && !$permissions['lead:leads:viewother']) {
2005
            return $this->accessDenied();
2006
        }
2007
2008
        /** @var LeadModel $leadModel */
2009
        $leadModel = $this->getModel('lead.lead');
2010
        $lead      = $leadModel->getEntity($contactId);
2011
        $dataType  = $this->request->get('filetype', 'csv');
2012
2013
        if (empty($lead)) {
2014
            return $this->notFound();
2015
        }
2016
2017
        $contactFields = $lead->getProfileFields();
2018
        $export        = [];
2019
        foreach ($contactFields as $alias => $contactField) {
2020
            $export[] = [
2021
                'alias' => $alias,
2022
                'value' => $contactField,
2023
            ];
2024
        }
2025
2026
        return $this->exportResultsAs($export, $dataType, 'contact_data_'.($contactFields['email'] ?: $contactFields['id']));
2027
    }
2028
}
2029