Issues (3627)

EventListener/LeadSubscriber.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * @copyright   2018 Mautic Inc. All rights reserved
7
 * @author      Mautic, Inc.
8
 *
9
 * @link        https://www.mautic.com
10
 *
11
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Mautic\IntegrationsBundle\EventListener;
15
16
use Mautic\IntegrationsBundle\Entity\FieldChange;
17
use Mautic\IntegrationsBundle\Entity\FieldChangeRepository;
18
use Mautic\IntegrationsBundle\Entity\ObjectMappingRepository;
19
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
20
use Mautic\IntegrationsBundle\Helper\SyncIntegrationsHelper;
21
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
22
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
23
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
24
use Mautic\IntegrationsBundle\Sync\VariableExpresser\VariableExpresserHelperInterface;
25
use Mautic\LeadBundle\Entity\Company;
26
use Mautic\LeadBundle\Entity\Lead;
27
use Mautic\LeadBundle\Event as Events;
28
use Mautic\LeadBundle\LeadEvents;
29
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
30
31
class LeadSubscriber implements EventSubscriberInterface
32
{
33
    /**
34
     * @var FieldChangeRepository
35
     */
36
    private $fieldChangeRepo;
37
38
    /**
39
     * @var ObjectMappingRepository
40
     */
41
    private $objectMappingRepository;
42
43
    /**
44
     * @var VariableExpresserHelperInterface
45
     */
46
    private $variableExpressor;
47
48
    /**
49
     * @var SyncIntegrationsHelper
50
     */
51
    private $syncIntegrationsHelper;
52
53
    public function __construct(
54
        FieldChangeRepository $fieldChangeRepo,
55
        ObjectMappingRepository $objectMappingRepository,
56
        VariableExpresserHelperInterface $variableExpressor,
57
        SyncIntegrationsHelper $syncIntegrationsHelper
58
    ) {
59
        $this->fieldChangeRepo         = $fieldChangeRepo;
60
        $this->objectMappingRepository = $objectMappingRepository;
61
        $this->variableExpressor       = $variableExpressor;
62
        $this->syncIntegrationsHelper  = $syncIntegrationsHelper;
63
    }
64
65
    public static function getSubscribedEvents(): array
66
    {
67
        return [
68
            LeadEvents::LEAD_POST_SAVE      => ['onLeadPostSave', 0],
69
            LeadEvents::LEAD_POST_DELETE    => ['onLeadPostDelete', 255],
70
            LeadEvents::COMPANY_POST_SAVE   => ['onCompanyPostSave', 0],
71
            LeadEvents::COMPANY_POST_DELETE => ['onCompanyPostDelete', 255],
72
            LeadEvents::LEAD_COMPANY_CHANGE => ['onLeadCompanyChange', 128],
73
        ];
74
    }
75
76
    /**
77
     * @throws IntegrationNotFoundException
78
     * @throws ObjectNotFoundException
79
     */
80
    public function onLeadPostSave(Events\LeadEvent $event): void
81
    {
82
        $lead = $event->getLead();
83
        if ($lead->isAnonymous()) {
84
            // Do not track visitor changes
85
            return;
86
        }
87
88
        if (defined('MAUTIC_INTEGRATION_SYNC_IN_PROGRESS')) {
89
            // Don't track changes just made by an active sync
90
            return;
91
        }
92
93
        if (!$this->syncIntegrationsHelper->hasObjectSyncEnabled(Contact::NAME)) {
94
            // Only track if an integration is syncing with contacts
95
            return;
96
        }
97
98
        $changes = $lead->getChanges(true);
99
100
        if (!empty($changes['owner'])) {
101
            // Force record of owner change if present in changelist
102
            $changes['fields']['owner_id'] = $changes['owner'];
103
        }
104
105
        if (!empty($changes['points'])) {
106
            // Add ability to update points custom field in target
107
            $changes['fields']['points'] = $changes['points'];
108
        }
109
110
        if (isset($changes['fields'])) {
111
            $this->recordFieldChanges($changes['fields'], $lead->getId(), Lead::class);
112
        }
113
114
        if (isset($changes['dnc_channel_status'])) {
115
            $dncChanges = [];
116
            foreach ($changes['dnc_channel_status'] as $channel => $change) {
117
                $oldValue = $change['old_reason'] ?? '';
118
                $newValue = $change['reason'];
119
120
                $dncChanges['mautic_internal_dnc_'.$channel] = [$oldValue, $newValue];
121
            }
122
123
            $this->recordFieldChanges($dncChanges, $lead->getId(), Lead::class);
124
        }
125
    }
126
127
    public function onLeadPostDelete(Events\LeadEvent $event): void
128
    {
129
        $this->fieldChangeRepo->deleteEntitiesForObject((int) $event->getLead()->deletedId, MauticSyncDataExchange::OBJECT_CONTACT);
130
        $this->objectMappingRepository->deleteEntitiesForObject((int) $event->getLead()->deletedId, MauticSyncDataExchange::OBJECT_CONTACT);
131
    }
132
133
    /**
134
     * @throws IntegrationNotFoundException
135
     * @throws ObjectNotFoundException
136
     */
137
    public function onCompanyPostSave(Events\CompanyEvent $event): void
138
    {
139
        if (defined('MAUTIC_INTEGRATION_SYNC_IN_PROGRESS')) {
140
            // Don't track changes just made by an active sync
141
            return;
142
        }
143
144
        if (!$this->syncIntegrationsHelper->hasObjectSyncEnabled(MauticSyncDataExchange::OBJECT_COMPANY)) {
145
            // Only track if an integration is syncing with companies
146
            return;
147
        }
148
149
        $company = $event->getCompany();
150
        $changes = $company->getChanges(true);
151
152
        if (!empty($changes['owner'])) {
153
            // Force record of owner change if present in changelist
154
            $changes['fields']['owner_id'] = $changes['owner'];
155
        }
156
157
        if (!isset($changes['fields'])) {
158
            return;
159
        }
160
161
        $this->recordFieldChanges($changes['fields'], $company->getId(), Company::class);
162
    }
163
164
    public function onCompanyPostDelete(Events\CompanyEvent $event): void
165
    {
166
        $this->fieldChangeRepo->deleteEntitiesForObject((int) $event->getCompany()->deletedId, MauticSyncDataExchange::OBJECT_COMPANY);
167
        $this->objectMappingRepository->deleteEntitiesForObject((int) $event->getCompany()->deletedId, MauticSyncDataExchange::OBJECT_COMPANY);
168
    }
169
170
    public function onLeadCompanyChange(Events\LeadChangeCompanyEvent $event): void
171
    {
172
        $lead = $event->getLead();
173
174
        // This mechanism is not able to record multiple company changes.
175
        $changes['company'] = [
0 ignored issues
show
Comprehensibility Best Practice introduced by
$changes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $changes = array(); before regardless.
Loading history...
176
            0 => '',
177
            1 => $lead->getCompany(),
178
        ];
179
180
        $this->recordFieldChanges($changes, $lead->getId(), Lead::class);
181
    }
182
183
    /**
184
     * @param int $objectId
185
     *
186
     * @throws IntegrationNotFoundException
187
     */
188
    private function recordFieldChanges(array $fieldChanges, $objectId, string $objectType): void
189
    {
190
        $toPersist     = [];
191
        $changedFields = [];
192
        $objectId      = (int) $objectId;
193
        foreach ($fieldChanges as $key => [$oldValue, $newValue]) {
194
            $valueDAO          = $this->variableExpressor->encodeVariable($newValue);
195
            $changedFields[]   = $key;
196
            $fieldChangeEntity = (new FieldChange())
197
                ->setObjectType($objectType)
198
                ->setObjectId($objectId)
199
                ->setModifiedAt(new \DateTime())
200
                ->setColumnName($key)
201
                ->setColumnType($valueDAO->getType())
202
                ->setColumnValue($valueDAO->getValue());
203
204
            foreach ($this->syncIntegrationsHelper->getEnabledIntegrations() as $integrationName) {
205
                $integrationFieldChangeEntity = clone $fieldChangeEntity;
206
                $integrationFieldChangeEntity->setIntegration($integrationName);
207
208
                $toPersist[] = $integrationFieldChangeEntity;
209
            }
210
        }
211
212
        $this->fieldChangeRepo->deleteEntitiesForObjectByColumnName($objectId, $objectType, $changedFields);
213
        $this->fieldChangeRepo->saveEntities($toPersist);
214
215
        $this->fieldChangeRepo->clear();
216
    }
217
}
218