chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?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;
}
}