![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/LeadBundle/Deduplicate/ |
<?php namespace Mautic\LeadBundle\Deduplicate; use Mautic\CoreBundle\Helper\ArrayHelper; use Mautic\LeadBundle\Deduplicate\Exception\SameContactException; use Mautic\LeadBundle\Deduplicate\Exception\ValueNotMergeableException; use Mautic\LeadBundle\Deduplicate\Helper\MergeValueHelper; use Mautic\LeadBundle\Entity\Lead; use Mautic\LeadBundle\Entity\MergeRecord; use Mautic\LeadBundle\Entity\MergeRecordRepository; use Mautic\LeadBundle\Event\LeadMergeEvent; use Mautic\LeadBundle\LeadEvents; use Mautic\LeadBundle\Model\LeadModel; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class ContactMerger { /** * @var Lead */ protected $winner; /** * @var Lead */ protected $loser; public function __construct( protected LeadModel $leadModel, protected MergeRecordRepository $repo, protected EventDispatcherInterface $dispatcher, protected LoggerInterface $logger ) { } /** * @throws SameContactException */ public function merge(Lead $winner, Lead $loser): Lead { if ($winner->getId() === $loser->getId()) { throw new SameContactException(); } $this->logger->debug('CONTACT: ID# '.$loser->getId().' will be merged into ID# '.$winner->getId()); // Dispatch pre merge event $event = new LeadMergeEvent($winner, $loser); $this->dispatcher->dispatch($event, LeadEvents::LEAD_PRE_MERGE); // Merge everything $this->updateMergeRecords($winner, $loser) ->mergeTimestamps($winner, $loser) ->mergeIpAddressHistory($winner, $loser) ->mergeFieldData($winner, $loser) ->mergeOwners($winner, $loser) ->mergePoints($winner, $loser) ->mergeTags($winner, $loser); // Save the updated contact $this->leadModel->saveEntity($winner, false); // Dispatch post merge event $this->dispatcher->dispatch($event, LeadEvents::LEAD_POST_MERGE); // Delete the loser $this->leadModel->deleteEntity($loser); return $winner; } /** * Merge timestamps. * * @return $this */ public function mergeTimestamps(Lead $winner, Lead $loser) { // The winner should keep the most recent last active timestamp of the two if ($loser->getLastActive() > $winner->getLastActive()) { $winner->setLastActive($loser->getLastActive()); } /* * The winner should keep the oldest date identified timestamp * as long as the loser's date identified is not null. * Alternatively, if the winner's date identified is null, * use the loser's date identified (doesn't matter if it is null). */ if ((null !== $loser->getDateIdentified() && $loser->getDateIdentified() < $winner->getDateIdentified()) || null === $winner->getDateIdentified()) { $winner->setDateIdentified($loser->getDateIdentified()); } return $this; } /** * Merge IP history into the winner. * * @return $this */ public function mergeIpAddressHistory(Lead $winner, Lead $loser) { $ipAddresses = $loser->getIpAddresses(); foreach ($ipAddresses as $ip) { $winner->addIpAddress($ip); $this->logger->debug('CONTACT: Associating '.$winner->getId().' with IP '.$ip->getIpAddress()); } return $this; } /** * Merge custom field data into winner. * * @return $this */ public function mergeFieldData(Lead $winner, Lead $loser) { // Use the modified date if applicable or date added if the contact has never been edited $loserDate = $loser->getDateModified() ?: $loser->getDateAdded(); $winnerDate = $winner->getDateModified() ?: $winner->getDateAdded(); // When it comes to data, keep the newest value regardless of the winner/loser $newest = ($loserDate > $winnerDate) ? $loser : $winner; $oldest = ($newest->getId() === $winner->getId()) ? $loser : $winner; // It may happen that the Lead entities doesn't have fields fill in. Fill them in if not. if (!$newest->hasFields()) { $newest->setFields($this->leadModel->getRepository()->getFieldValues($newest->getId())); } if (!$oldest->hasFields()) { $oldest->setFields($this->leadModel->getRepository()->getFieldValues($oldest->getId())); } $newestFields = $newest->getProfileFields(); $oldestFields = $oldest->getProfileFields(); foreach (array_keys($newestFields) as $field) { if (in_array($field, ['id', 'points'])) { // Let mergePoints() take care of this continue; } try { $fromValue = empty($oldestFields[$field]) ? 'empty' : $oldestFields[$field]; $fieldDetails = $winner->getField($field); if (false === $fieldDetails) { throw new ValueNotMergeableException($fromValue, false); } $defaultValue = ArrayHelper::getValue('default_value', $fieldDetails); $newValue = MergeValueHelper::getMergeValue( $newestFields[$field], $oldestFields[$field], $winner->getFieldValue($field), $defaultValue, $newest->isAnonymous() ); $winner->addUpdatedField($field, $newValue); $this->logger->debug("CONTACT: Updated {$field} from {$fromValue} to {$newValue} for {$winner->getId()}"); } catch (ValueNotMergeableException $exception) { $this->logger->info("CONTACT: {$field} is not mergeable for {$winner->getId()} - {$exception->getMessage()}"); } } return $this; } /** * Merge owners if the winner isn't already assigned an owner. * * @return $this */ public function mergeOwners(Lead $winner, Lead $loser) { $oldOwner = $winner->getOwner(); $newOwner = $loser->getOwner(); if (null === $oldOwner && null !== $newOwner) { $winner->setOwner($newOwner); $this->logger->debug("CONTACT: New owner of {$winner->getId()} is {$newOwner->getId()}"); } return $this; } /** * Sum points from both contacts. * * @return $this */ public function mergePoints(Lead $winner, Lead $loser) { $winnerPoints = (int) $winner->getPoints(); $loserPoints = (int) $loser->getPoints(); $winner->adjustPoints($loserPoints); $this->logger->debug( 'CONTACT: Adding '.$loserPoints.' points from contact ID #'.$loser->getId().' to contact ID #'.$winner->getId().' with '.$winnerPoints .' points' ); return $this; } /** * Merge tags from loser into winner. * * @return $this */ public function mergeTags(Lead $winner, Lead $loser) { $loserTags = $loser->getTags(); $addTags = $loserTags->getKeys(); $this->leadModel->modifyTags($winner, $addTags, null, false); return $this; } /** * Merge past merge records into the winner. * * @return $this */ private function updateMergeRecords(Lead $winner, Lead $loser) { // Update merge records for the lead about to be deleted $this->repo->moveMergeRecord($loser->getId(), $winner->getId()); // Create an entry this contact was merged $mergeRecord = new MergeRecord(); $mergeRecord->setContact($winner) ->setDateAdded() ->setName($loser->getPrimaryIdentifier()) ->setMergedId($loser->getId()); $this->repo->saveEntity($mergeRecord); return $this; } }