Issues (3627)

CampaignBundle/Membership/MembershipBuilder.php (2 issues)

1
<?php
2
3
/*
4
 * @copyright   2018 Mautic Contributors. All rights reserved
5
 * @author      Mautic, Inc.
6
 *
7
 * @link        https://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace Mautic\CampaignBundle\Membership;
13
14
use Mautic\CampaignBundle\Entity\Campaign;
15
use Mautic\CampaignBundle\Entity\LeadRepository as CampaignMemberRepository;
16
use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter;
17
use Mautic\CampaignBundle\Membership\Exception\RunLimitReachedException;
18
use Mautic\CoreBundle\Helper\ProgressBarHelper;
19
use Mautic\LeadBundle\Entity\LeadRepository;
20
use Symfony\Component\Console\Helper\ProgressBar;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Translation\TranslatorInterface;
23
24
class MembershipBuilder
25
{
26
    /**
27
     * @var MembershipManager
28
     */
29
    private $manager;
30
31
    /**
32
     * @var CampaignMemberRepository
33
     */
34
    private $campaignMemberRepository;
35
36
    /**
37
     * @var LeadRepository
38
     */
39
    private $leadRepository;
40
41
    /**
42
     * @var TranslatorInterface
43
     */
44
    private $translator;
45
46
    /**
47
     * @var Campaign
48
     */
49
    private $campaign;
50
51
    /**
52
     * @var ContactLimiter
53
     */
54
    private $contactLimiter;
55
56
    /**
57
     * @var int
58
     */
59
    private $runLimit;
60
61
    /**
62
     * @var OutputInterface|null
63
     */
64
    private $output;
65
66
    /**
67
     * @var ProgressBar|null
68
     */
69
    private $progressBar;
70
71
    public function __construct(
72
        MembershipManager $manager,
73
        CampaignMemberRepository $campaignMemberRepository,
74
        LeadRepository $leadRepository,
75
        TranslatorInterface $translator
76
    ) {
77
        $this->manager                  = $manager;
78
        $this->campaignMemberRepository = $campaignMemberRepository;
79
        $this->leadRepository           = $leadRepository;
80
        $this->translator               = $translator;
81
    }
82
83
    /**
84
     * @param int $runLimit
85
     *
86
     * @return int
87
     */
88
    public function build(Campaign $campaign, ContactLimiter $contactLimiter, $runLimit, OutputInterface $output = null)
89
    {
90
        defined('MAUTIC_REBUILDING_CAMPAIGNS') or define('MAUTIC_REBUILDING_CAMPAIGNS', 1);
91
92
        $this->campaign       = $campaign;
93
        $this->contactLimiter = $contactLimiter;
94
        $this->runLimit       = (int) $runLimit;
95
        $this->output         = $output;
96
97
        $contactsProcessed = 0;
98
99
        try {
100
            $contactsProcessed += $this->addNewlyQualifiedMembers($contactsProcessed);
101
        } catch (RunLimitReachedException $exception) {
102
            return $exception->getContactsProcessed();
103
        }
104
105
        try {
106
            $contactsProcessed += $this->removeUnqualifiedMembers($contactsProcessed);
107
        } catch (RunLimitReachedException $exception) {
108
            return $exception->getContactsProcessed();
109
        }
110
111
        return $contactsProcessed;
112
    }
113
114
    /**
115
     * @param $totalContactsProcessed
116
     *
117
     * @return int
118
     *
119
     * @throws RunLimitReachedException
120
     */
121
    private function addNewlyQualifiedMembers($totalContactsProcessed)
122
    {
123
        $progress          = null;
0 ignored issues
show
The assignment to $progress is dead and can be removed.
Loading history...
124
        $contactsProcessed = 0;
125
126
        if ($this->output) {
127
            $countResult = $this->campaignMemberRepository->getCountsForCampaignContactsBySegment($this->campaign->getId(), $this->contactLimiter, $this->campaign->allowRestart());
128
129
            $this->output->writeln(
130
                $this->translator->trans(
131
                    'mautic.campaign.rebuild.to_be_added',
132
                    ['%leads%' => $countResult->getCount(), '%batch%' => $this->contactLimiter->getBatchLimit()]
133
                )
134
            );
135
136
            if (0 === $countResult->getCount()) {
137
                // No use continuing
138
                return 0;
139
            }
140
141
            $this->startProgressBar($countResult->getCount());
142
        }
143
144
        $contacts = $this->campaignMemberRepository->getCampaignContactsBySegments($this->campaign->getId(), $this->contactLimiter, $this->campaign->allowRestart());
145
146
        while (count($contacts)) {
147
            $contactCollection = $this->leadRepository->getContactCollection($contacts);
148
            if (!$contactCollection->count()) {
149
                // Prevent endless loop just in case
150
                break;
151
            }
152
153
            $contactsProcessed += $contactCollection->count();
154
155
            // Add the contacts to this segment
156
            $this->manager->addContacts($contactCollection, $this->campaign, false);
157
158
            // Clear Lead entities from RAM
159
            $this->leadRepository->clear();
160
161
            // Have we hit the run limit?
162
            if ($this->runLimit && $contactsProcessed >= $this->runLimit) {
163
                $this->finishProgressBar();
164
                throw new RunLimitReachedException($contactsProcessed + $totalContactsProcessed);
165
            }
166
167
            // Get next batch
168
            $contacts = $this->campaignMemberRepository->getCampaignContactsBySegments($this->campaign->getId(), $this->contactLimiter);
169
        }
170
171
        $this->finishProgressBar();
172
173
        return $contactsProcessed;
174
    }
175
176
    /**
177
     * @param $totalContactsProcessed
178
     *
179
     * @return int
180
     *
181
     * @throws RunLimitReachedException
182
     */
183
    private function removeUnqualifiedMembers($totalContactsProcessed)
184
    {
185
        $progress          = null;
0 ignored issues
show
The assignment to $progress is dead and can be removed.
Loading history...
186
        $contactsProcessed = 0;
187
188
        if ($this->output) {
189
            $countResult = $this->campaignMemberRepository->getCountsForOrphanedContactsBySegments($this->campaign->getId(), $this->contactLimiter);
190
191
            $this->output->writeln(
192
                $this->translator->trans(
193
                    'mautic.lead.list.rebuild.to_be_removed',
194
                    ['%leads%' => $countResult->getCount(), '%batch%' => $this->contactLimiter->getBatchLimit()]
195
                )
196
            );
197
198
            if (0 === $countResult->getCount()) {
199
                // No use continuing
200
                return 0;
201
            }
202
203
            $this->startProgressBar($countResult->getCount());
204
        }
205
206
        $contacts = $this->campaignMemberRepository->getOrphanedContacts($this->campaign->getId(), $this->contactLimiter);
207
        while (count($contacts)) {
208
            $contactCollection = $this->leadRepository->getContactCollection($contacts);
209
            if (!$contactCollection->count()) {
210
                // Prevent endless loop just in case
211
                break;
212
            }
213
214
            $contactsProcessed += $contactCollection->count();
215
216
            // Add the contacts to this segment
217
            $this->manager->removeContacts($contactCollection, $this->campaign, true);
218
219
            // Clear Lead entities from RAM
220
            $this->leadRepository->clear();
221
222
            // Have we hit the run limit?
223
            if ($this->runLimit && $contactsProcessed >= $this->runLimit) {
224
                $this->finishProgressBar();
225
                throw new RunLimitReachedException($contactsProcessed + $totalContactsProcessed);
226
            }
227
228
            // Get next batch
229
            $contacts = $this->campaignMemberRepository->getOrphanedContacts($this->campaign->getId(), $this->contactLimiter);
230
        }
231
232
        $this->finishProgressBar();
233
234
        return $contactsProcessed;
235
    }
236
237
    /**
238
     * @param $total
239
     */
240
    private function startProgressBar($total)
241
    {
242
        if (!$this->output) {
243
            $this->progressBar = null;
244
            $this->manager->setProgressBar($this->progressBar);
245
246
            return;
247
        }
248
249
        $this->progressBar = ProgressBarHelper::init($this->output, $total);
250
        $this->progressBar->start();
251
252
        // Notify the manager to increment progress as contacts are added
253
        $this->manager->setProgressBar($this->progressBar);
254
    }
255
256
    private function finishProgressBar()
257
    {
258
        if ($this->progressBar) {
259
            $this->progressBar->finish();
260
            $this->output->writeln('');
261
        }
262
    }
263
}
264