239 lines
8.2 KiB
PHP
Executable File
239 lines
8.2 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Mautic\CampaignBundle\Command;
|
|
|
|
use Mautic\CampaignBundle\Entity\Campaign;
|
|
use Mautic\CampaignBundle\Entity\CampaignRepository;
|
|
use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter;
|
|
use Mautic\CampaignBundle\Membership\MembershipBuilder;
|
|
use Mautic\CoreBundle\Command\ModeratedCommand;
|
|
use Mautic\CoreBundle\Helper\CoreParametersHelper;
|
|
use Mautic\CoreBundle\Helper\PathsHelper;
|
|
use Mautic\CoreBundle\Twig\Helper\FormatterHelper;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\Console\Attribute\AsCommand;
|
|
use Symfony\Component\Console\Input\InputInterface;
|
|
use Symfony\Component\Console\Input\InputOption;
|
|
use Symfony\Component\Console\Output\NullOutput;
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
|
|
#[AsCommand(
|
|
name: 'mautic:campaigns:rebuild',
|
|
description: 'Rebuild campaigns based on contact segments.',
|
|
aliases: ['mautic:campaigns:update']
|
|
)]
|
|
class UpdateLeadCampaignsCommand extends ModeratedCommand
|
|
{
|
|
private int $runLimit = 0;
|
|
|
|
private ContactLimiter $contactLimiter;
|
|
|
|
private bool $quiet = false;
|
|
|
|
public function __construct(
|
|
private CampaignRepository $campaignRepository,
|
|
private TranslatorInterface $translator,
|
|
private MembershipBuilder $membershipBuilder,
|
|
private LoggerInterface $logger,
|
|
private FormatterHelper $formatterHelper,
|
|
PathsHelper $pathsHelper,
|
|
CoreParametersHelper $coreParametersHelper,
|
|
) {
|
|
parent::__construct($pathsHelper, $coreParametersHelper);
|
|
}
|
|
|
|
protected function configure()
|
|
{
|
|
$this
|
|
->addOption('--batch-limit', '-l', InputOption::VALUE_OPTIONAL, 'Set batch size of contacts to process per round. Defaults to 300.', 300)
|
|
->addOption(
|
|
'--max-contacts',
|
|
'-m',
|
|
InputOption::VALUE_OPTIONAL,
|
|
'Set max number of contacts to process per campaign for this script execution. Defaults to all.',
|
|
0
|
|
)
|
|
->addOption(
|
|
'--campaign-id',
|
|
'-i',
|
|
InputOption::VALUE_OPTIONAL,
|
|
'Build membership for a specific campaign. Otherwise, all campaigns will be rebuilt.',
|
|
null
|
|
)
|
|
->addOption(
|
|
'--contact-id',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'Build membership for a specific contact.',
|
|
null
|
|
)
|
|
->addOption(
|
|
'--contact-ids',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'CSV of contact IDs to evaluate.'
|
|
)
|
|
->addOption(
|
|
'--min-contact-id',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'Build membership starting at a specific contact ID.',
|
|
null
|
|
)
|
|
->addOption(
|
|
'--max-contact-id',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'Build membership up to a specific contact ID.',
|
|
null
|
|
)
|
|
->addOption(
|
|
'--thread-id',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'The number of this current process if running multiple in parallel.'
|
|
)
|
|
->addOption(
|
|
'--max-threads',
|
|
null,
|
|
InputOption::VALUE_OPTIONAL,
|
|
'The maximum number of processes you intend to run in parallel.'
|
|
)
|
|
->addOption(
|
|
'exclude',
|
|
'd',
|
|
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
|
|
'Exclude a specific campaign from being rebuilt. Otherwise, all campaigns will be rebuilt.',
|
|
[]
|
|
);
|
|
|
|
parent::configure();
|
|
}
|
|
|
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
|
{
|
|
$id = $input->getOption('campaign-id');
|
|
$batchLimit = $input->getOption('batch-limit');
|
|
$contactMinId = $input->getOption('min-contact-id');
|
|
$contactMaxId = $input->getOption('max-contact-id');
|
|
$contactId = $input->getOption('contact-id');
|
|
$contactIds = $this->formatterHelper->simpleCsvToArray($input->getOption('contact-ids'), 'int');
|
|
$threadId = $input->getOption('thread-id');
|
|
$maxThreads = $input->getOption('max-threads');
|
|
$this->runLimit = $input->getOption('max-contacts');
|
|
$this->quiet = (bool) $input->getOption('quiet');
|
|
$this->output = ($this->quiet) ? new NullOutput() : $output;
|
|
$excludeCampaigns = $input->getOption('exclude');
|
|
|
|
if (is_numeric($id)) {
|
|
$id = (int) $id;
|
|
}
|
|
|
|
if (is_numeric($maxThreads)) {
|
|
$maxThreads = (int) $maxThreads;
|
|
}
|
|
|
|
if (is_numeric($threadId)) {
|
|
$threadId = (int) $threadId;
|
|
}
|
|
|
|
if (is_numeric($contactMaxId)) {
|
|
$contactMaxId = (int) $contactMaxId;
|
|
}
|
|
|
|
if (is_numeric($contactMinId)) {
|
|
$contactMinId = (int) $contactMinId;
|
|
}
|
|
|
|
if (is_numeric($contactId)) {
|
|
$contactId = (int) $contactId;
|
|
}
|
|
|
|
if ($threadId && $maxThreads && (int) $threadId > (int) $maxThreads) {
|
|
$this->output->writeln('--thread-id cannot be larger than --max-thread');
|
|
|
|
return \Symfony\Component\Console\Command\Command::FAILURE;
|
|
}
|
|
|
|
if (!$this->checkRunStatus($input, $output, $id)) {
|
|
return \Symfony\Component\Console\Command\Command::SUCCESS;
|
|
}
|
|
|
|
$this->contactLimiter = new ContactLimiter($batchLimit, $contactId, $contactMinId, $contactMaxId, $contactIds, $threadId, $maxThreads);
|
|
|
|
if ($id) {
|
|
$campaign = $this->campaignRepository->getEntity($id);
|
|
if (null === $campaign) {
|
|
$output->writeln('<error>'.$this->translator->trans('mautic.campaign.rebuild.not_found', ['%id%' => $id]).'</error>');
|
|
|
|
return \Symfony\Component\Console\Command\Command::FAILURE;
|
|
}
|
|
|
|
$this->updateCampaign($campaign);
|
|
} else {
|
|
$filter = [
|
|
'iterable_mode' => true,
|
|
];
|
|
|
|
if (is_array($excludeCampaigns) && count($excludeCampaigns) > 0) {
|
|
$filter['filter'] = [
|
|
'force' => [
|
|
[
|
|
'expr' => 'notIn',
|
|
'column' => $this->campaignRepository->getTableAlias().'.id',
|
|
'value' => $excludeCampaigns,
|
|
],
|
|
],
|
|
];
|
|
}
|
|
$campaigns = $this->campaignRepository->getEntities($filter);
|
|
|
|
foreach ($campaigns as $campaign) {
|
|
$this->updateCampaign($campaign);
|
|
|
|
unset($campaign);
|
|
}
|
|
}
|
|
|
|
$this->completeRun();
|
|
|
|
return \Symfony\Component\Console\Command\Command::SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @throws \Exception
|
|
*/
|
|
private function updateCampaign(Campaign $campaign): void
|
|
{
|
|
if (!$campaign->isPublished()) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$this->output->writeln(
|
|
'<info>'.$this->translator->trans('mautic.campaign.rebuild.rebuilding', ['%id%' => $campaign->getId()]).'</info>'
|
|
);
|
|
|
|
// Reset batch limiter
|
|
$this->contactLimiter->resetBatchMinContactId();
|
|
|
|
$this->membershipBuilder->build($campaign, $this->contactLimiter, $this->runLimit, ($this->quiet) ? null : $this->output);
|
|
} catch (\Exception $exception) {
|
|
if ('prod' !== MAUTIC_ENV) {
|
|
// Throw the exception for dev/test mode
|
|
throw $exception;
|
|
}
|
|
|
|
$this->logger->error('CAMPAIGN: '.$exception->getMessage());
|
|
}
|
|
|
|
// Don't detach in tests since this command will be ran multiple times in the same process
|
|
if ('test' !== MAUTIC_ENV) {
|
|
$this->campaignRepository->detachEntity($campaign);
|
|
}
|
|
|
|
$this->output->writeln('');
|
|
}
|
|
}
|