Spaces:
No application file
No application file
namespace Mautic\CampaignBundle\Membership; | |
use Doctrine\Common\Collections\ArrayCollection; | |
use Mautic\CampaignBundle\Entity\Campaign; | |
use Mautic\CampaignBundle\Entity\Lead as CampaignMember; | |
use Mautic\CampaignBundle\Entity\LeadRepository; | |
use Mautic\CampaignBundle\Membership\Action\Adder; | |
use Mautic\CampaignBundle\Membership\Action\Remover; | |
use Mautic\CampaignBundle\Membership\Exception\ContactAlreadyRemovedFromCampaignException; | |
use Mautic\CampaignBundle\Membership\Exception\ContactCannotBeAddedToCampaignException; | |
use Mautic\LeadBundle\Entity\Lead; | |
use Psr\Log\LoggerInterface; | |
use Symfony\Component\Console\Helper\ProgressBar; | |
class MembershipManager | |
{ | |
public const ACTION_ADDED = 'added'; | |
public const ACTION_REMOVED = 'removed'; | |
private ?ProgressBar $progressBar = null; | |
public function __construct( | |
private Adder $adder, | |
private Remover $remover, | |
private EventDispatcher $eventDispatcher, | |
private LeadRepository $leadRepository, | |
private LoggerInterface $logger | |
) { | |
} | |
/** | |
* @param bool $isManualAction | |
*/ | |
public function addContact(Lead $contact, Campaign $campaign, $isManualAction = true): void | |
{ | |
// Validate that contact is not already in the Campaign | |
/** @var CampaignMember $campaignMember */ | |
$campaignMember = $this->leadRepository->findOneBy( | |
[ | |
'lead' => $contact, | |
'campaign' => $campaign, | |
] | |
); | |
if ($campaignMember) { | |
try { | |
$this->adder->updateExistingMembership($campaignMember, $isManualAction); | |
$this->logger->debug( | |
"CAMPAIGN: Membership for contact ID {$contact->getId()} in campaign ID {$campaign->getId()} was updated to be included." | |
); | |
// Notify listeners | |
$this->eventDispatcher->dispatchMembershipChange($campaignMember->getLead(), $campaignMember->getCampaign(), Adder::NAME); | |
} catch (ContactCannotBeAddedToCampaignException $exception) { | |
// Do nothing | |
$this->logger->debug( | |
"CAMPAIGN: Contact ID {$contact->getId()} could not be added to campaign ID {$campaign->getId()}.", | |
$exception->toArray() | |
); | |
} | |
return; | |
} | |
try { | |
// Contact is not already in the campaign so create a new entry | |
$this->adder->createNewMembership($contact, $campaign, $isManualAction); | |
} catch (ContactCannotBeAddedToCampaignException $exception) { | |
// Do nothing | |
$this->logger->debug( | |
"CAMPAIGN: Contact ID {$contact->getId()} could not be added to campaign ID {$campaign->getId()}.", | |
$exception->toArray() | |
); | |
return; | |
} | |
$this->logger->debug("CAMPAIGN: Contact ID {$contact->getId()} was added to campaign ID {$campaign->getId()} as a new member."); | |
// Notify listeners the contact has been added | |
$this->eventDispatcher->dispatchMembershipChange($contact, $campaign, Adder::NAME); | |
} | |
/** | |
* @param ArrayCollection<int, Lead> $contacts | |
* @param bool $isManualAction | |
*/ | |
public function addContacts(ArrayCollection $contacts, Campaign $campaign, $isManualAction = true): void | |
{ | |
// Get a list of existing campaign members | |
$campaignMembers = $this->leadRepository->getCampaignMembers($contacts->getKeys(), $campaign); | |
foreach ($contacts as $contact) { | |
$this->advanceProgressBar(); | |
$this->logger->debug( | |
'CAMPAIGN: Contacts: '.count($contacts), | |
array_map(fn ($item) => $item->getId(), $contacts->toArray()) | |
); | |
// is the contact an existing campaign member? update and continue | |
if (isset($campaignMembers[$contact->getId()])) { | |
try { | |
$this->adder->updateExistingMembership($campaignMembers[$contact->getId()], $isManualAction); | |
$this->logger->debug( | |
"CAMPAIGN: Membership for contact ID {$contact->getId()} in campaign ID {$campaign->getId()} was updated to be included." | |
); | |
} catch (ContactCannotBeAddedToCampaignException $exception) { | |
$contacts->remove($contact->getId()); | |
$this->logger->debug( | |
"CAMPAIGN: Contact ID {$contact->getId()} could not be added to campaign ID {$campaign->getId()}.", | |
$exception->toArray() | |
); | |
} | |
continue; | |
} | |
// Existing membership does not exist so create a new one | |
$this->adder->createNewMembership($contact, $campaign, $isManualAction); | |
$this->logger->debug("CAMPAIGN: Contact ID {$contact->getId()} was added to campaign ID {$campaign->getId()} as a new member."); | |
} | |
if ($contacts->count()) { | |
// Notifiy listeners | |
$this->eventDispatcher->dispatchBatchMembershipChange($contacts->toArray(), $campaign, Adder::NAME); | |
} | |
// Clear entities from RAM | |
$this->leadRepository->detachEntities($contacts->toArray()); | |
} | |
/** | |
* @param bool $isExit | |
*/ | |
public function removeContact(Lead $contact, Campaign $campaign, $isExit = false): void | |
{ | |
// Validate that contact is not already in the Campaign | |
/** @var CampaignMember $campaignMember */ | |
$campaignMember = $this->leadRepository->findOneBy( | |
[ | |
'lead' => $contact, | |
'campaign' => $campaign, | |
] | |
); | |
if (!$campaignMember) { | |
// Contact is not in this campaign | |
$this->logger->debug("CAMPAIGN: Contact ID {$contact->getId()} is not in campaign ID {$campaign->getId()}."); | |
return; | |
} | |
try { | |
$this->remover->updateExistingMembership($campaignMember, $isExit); | |
$this->logger->debug("CAMPAIGN: Contact ID {$contact->getId()} was removed from campaign ID {$campaign->getId()}."); | |
// Notify listeners | |
$this->eventDispatcher->dispatchMembershipChange($contact, $campaign, Remover::NAME); | |
} catch (ContactAlreadyRemovedFromCampaignException $exception) { | |
// Do nothing | |
$this->logger->debug( | |
"CAMPAIGN: Contact ID {$contact->getId()} was already removed from campaign ID {$campaign->getId()}.", | |
$exception->toArray() | |
); | |
} | |
} | |
/** | |
* @param ArrayCollection<int, Lead> $contacts | |
* @param bool $isExit If true, the contact can be added by a segment/source. If false, the contact can only be added back | |
* by a manual process. | |
*/ | |
public function removeContacts(ArrayCollection $contacts, Campaign $campaign, $isExit = false): void | |
{ | |
// Get a list of existing campaign members | |
$campaignMembers = $this->leadRepository->getCampaignMembers($contacts->getKeys(), $campaign); | |
foreach ($contacts as $contact) { | |
$this->advanceProgressBar(); | |
if (!isset($campaignMembers[$contact->getId()])) { | |
// Contact is not in the campaign | |
$contacts->remove($contact->getId()); | |
continue; | |
} | |
/** @var CampaignMember $campaignMember */ | |
$campaignMember = $campaignMembers[$contact->getId()]; | |
try { | |
$this->remover->updateExistingMembership($campaignMember, $isExit); | |
$this->logger->debug("CAMPAIGN: Contact ID {$contact->getId()} was removed from campaign ID {$campaign->getId()}."); | |
} catch (ContactAlreadyRemovedFromCampaignException $exception) { | |
// Contact was already removed from this campaign | |
$contacts->remove($contact->getId()); | |
$this->logger->debug( | |
"CAMPAIGN: Contact ID {$contact->getId()} was already removed from campaign ID {$campaign->getId()}.", | |
$exception->toArray() | |
); | |
} | |
} | |
if ($contacts->count()) { | |
// Notify listeners | |
$this->eventDispatcher->dispatchBatchMembershipChange($contacts->toArray(), $campaign, Remover::NAME); | |
} | |
// Clear entities from RAM | |
$this->leadRepository->detachEntities($campaignMembers); | |
} | |
public function setProgressBar(ProgressBar $progressBar = null): void | |
{ | |
$this->progressBar = $progressBar; | |
} | |
private function advanceProgressBar(): void | |
{ | |
if ($this->progressBar) { | |
$this->progressBar->advance(); | |
} | |
} | |
} | |