1 | <?php |
||
2 | |||
3 | /* |
||
4 | * @copyright 2014 Mautic Contributors. All rights reserved |
||
5 | * @author Mautic |
||
6 | * |
||
7 | * @link http://mautic.org |
||
8 | * |
||
9 | * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html |
||
10 | */ |
||
11 | |||
12 | namespace Mautic\CampaignBundle\Entity; |
||
13 | |||
14 | use Doctrine\DBAL\Connection; |
||
15 | use Doctrine\DBAL\Query\QueryBuilder; |
||
16 | use Mautic\CampaignBundle\Entity\Result\CountResult; |
||
17 | use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter; |
||
18 | use Mautic\CoreBundle\Entity\CommonRepository; |
||
19 | |||
20 | class LeadRepository extends CommonRepository |
||
21 | { |
||
22 | use ContactLimiterTrait; |
||
23 | use SlaveConnectionTrait; |
||
24 | |||
25 | /** |
||
26 | * Get the details of leads added to a campaign. |
||
27 | * |
||
28 | * @param $campaignId |
||
29 | * @param null $leads |
||
30 | * |
||
31 | * @return array |
||
32 | */ |
||
33 | public function getLeadDetails($campaignId, $leads = null) |
||
34 | { |
||
35 | $q = $this->getEntityManager()->createQueryBuilder() |
||
36 | ->from('MauticCampaignBundle:Lead', 'lc') |
||
37 | ->select('lc') |
||
38 | ->leftJoin('lc.campaign', 'c') |
||
39 | ->leftJoin('lc.lead', 'l'); |
||
40 | $q->where( |
||
41 | $q->expr()->eq('c.id', ':campaign') |
||
42 | )->setParameter('campaign', $campaignId); |
||
43 | |||
44 | if (!empty($leads)) { |
||
45 | $q->andWhere( |
||
46 | $q->expr()->in('l.id', ':leads') |
||
47 | )->setParameter('leads', $leads); |
||
48 | } |
||
49 | |||
50 | $results = $q->getQuery()->getArrayResult(); |
||
51 | |||
52 | $return = []; |
||
53 | foreach ($results as $r) { |
||
54 | $return[$r['lead_id']][] = $r; |
||
55 | } |
||
56 | |||
57 | return $return; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Get leads for a specific campaign. |
||
62 | * |
||
63 | * @param $campaignId |
||
64 | * @param null $eventId |
||
65 | * |
||
66 | * @return array |
||
67 | */ |
||
68 | public function getLeads($campaignId, $eventId = null) |
||
69 | { |
||
70 | $q = $this->getEntityManager()->createQueryBuilder() |
||
71 | ->from('MauticCampaignBundle:Lead', 'lc') |
||
72 | ->select('lc, l') |
||
73 | ->leftJoin('lc.campaign', 'c') |
||
74 | ->leftJoin('lc.lead', 'l'); |
||
75 | $q->where( |
||
76 | $q->expr()->andX( |
||
77 | $q->expr()->eq('lc.manuallyRemoved', ':false'), |
||
78 | $q->expr()->eq('c.id', ':campaign') |
||
79 | ) |
||
80 | ) |
||
81 | ->setParameter('false', false, 'boolean') |
||
82 | ->setParameter('campaign', $campaignId); |
||
83 | |||
84 | if (null != $eventId) { |
||
85 | $dq = $this->getEntityManager()->createQueryBuilder(); |
||
86 | $dq->select('el.id') |
||
87 | ->from('MauticCampaignBundle:LeadEventLog', 'ell') |
||
88 | ->leftJoin('ell.lead', 'el') |
||
89 | ->leftJoin('ell.event', 'ev') |
||
90 | ->where( |
||
91 | $dq->expr()->eq('ev.id', ':eventId') |
||
92 | ); |
||
93 | |||
94 | $q->andWhere('l.id NOT IN('.$dq->getDQL().')') |
||
95 | ->setParameter('eventId', $eventId); |
||
96 | } |
||
97 | |||
98 | return $q->getQuery()->getResult(); |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Updates lead ID (e.g. after a lead merge). |
||
103 | * |
||
104 | * @param $fromLeadId |
||
105 | * @param $toLeadId |
||
106 | */ |
||
107 | public function updateLead($fromLeadId, $toLeadId) |
||
108 | { |
||
109 | // First check to ensure the $toLead doesn't already exist |
||
110 | $results = $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
111 | ->select('cl.campaign_id') |
||
112 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
113 | ->where('cl.lead_id = '.$toLeadId) |
||
114 | ->execute() |
||
115 | ->fetchAll(); |
||
116 | $campaigns = []; |
||
117 | foreach ($results as $r) { |
||
118 | $campaigns[] = $r['campaign_id']; |
||
119 | } |
||
120 | |||
121 | $q = $this->getEntityManager()->getConnection()->createQueryBuilder(); |
||
122 | $q->update(MAUTIC_TABLE_PREFIX.'campaign_leads') |
||
123 | ->set('lead_id', (int) $toLeadId) |
||
124 | ->where('lead_id = '.(int) $fromLeadId); |
||
125 | |||
126 | if (!empty($campaigns)) { |
||
127 | $q->andWhere( |
||
128 | $q->expr()->notIn('campaign_id', $campaigns) |
||
129 | )->execute(); |
||
130 | |||
131 | // Delete remaining leads as the new lead already belongs |
||
132 | $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
133 | ->delete(MAUTIC_TABLE_PREFIX.'campaign_leads') |
||
134 | ->where('lead_id = '.(int) $fromLeadId) |
||
135 | ->execute(); |
||
136 | } else { |
||
137 | $q->execute(); |
||
138 | } |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Check Lead in campaign. |
||
143 | * |
||
144 | * @param Lead $lead |
||
145 | * @param array $options |
||
146 | * |
||
147 | * @return bool |
||
148 | */ |
||
149 | public function checkLeadInCampaigns($lead, $options = []) |
||
150 | { |
||
151 | if (empty($options['campaigns'])) { |
||
152 | return false; |
||
153 | } |
||
154 | $q = $this->_em->getConnection()->createQueryBuilder(); |
||
155 | $q->select('l.campaign_id') |
||
156 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'l'); |
||
157 | $q->where( |
||
158 | $q->expr()->andX( |
||
159 | $q->expr()->eq('l.lead_id', ':leadId'), |
||
160 | $q->expr()->in('l.campaign_id', $options['campaigns'], \Doctrine\DBAL\Connection::PARAM_INT_ARRAY) |
||
161 | ) |
||
162 | ); |
||
163 | |||
164 | if (!empty($options['dataAddedLimit'])) { |
||
165 | $q->andWhere($q->expr() |
||
166 | ->{$options['expr']}('l.date_added', ':dateAdded')) |
||
167 | ->setParameter('dateAdded', $options['dateAdded']); |
||
168 | } |
||
169 | |||
170 | $q->setParameter('leadId', $lead->getId()); |
||
0 ignored issues
–
show
|
|||
171 | |||
172 | return (bool) $q->execute()->fetchColumn(); |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * @param int $campaignId |
||
177 | * @param int $decisionId |
||
178 | * @param int $parentDecisionId |
||
179 | * |
||
180 | * @return array |
||
181 | */ |
||
182 | public function getInactiveContacts($campaignId, $decisionId, $parentDecisionId, ContactLimiter $limiter) |
||
183 | { |
||
184 | // Main query |
||
185 | $q = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
186 | $q->select('l.lead_id, l.date_added') |
||
187 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'l') |
||
188 | ->where( |
||
189 | $q->expr()->andX( |
||
190 | $q->expr()->eq('l.campaign_id', ':campaignId'), |
||
191 | $q->expr()->eq('l.manually_removed', 0) |
||
192 | ) |
||
193 | ) |
||
194 | // Order by ID so we can query by greater than X contact ID when batching |
||
195 | ->orderBy('l.lead_id') |
||
196 | ->setMaxResults($limiter->getBatchLimit()) |
||
197 | ->setParameter('campaignId', (int) $campaignId) |
||
198 | ->setParameter('decisionId', (int) $decisionId); |
||
199 | |||
200 | // Contact IDs |
||
201 | $this->updateQueryFromContactLimiter('l', $q, $limiter); |
||
202 | |||
203 | // Limit to events that have not been executed or scheduled yet |
||
204 | $eventQb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
205 | $eventQb->select('null') |
||
206 | ->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'log') |
||
207 | ->where( |
||
208 | $eventQb->expr()->andX( |
||
209 | $eventQb->expr()->eq('log.event_id', ':decisionId'), |
||
210 | $eventQb->expr()->eq('log.lead_id', 'l.lead_id'), |
||
211 | $eventQb->expr()->eq('log.rotation', 'l.rotation') |
||
212 | ) |
||
213 | ); |
||
214 | $q->andWhere( |
||
215 | sprintf('NOT EXISTS (%s)', $eventQb->getSQL()) |
||
216 | ); |
||
217 | |||
218 | if ($parentDecisionId) { |
||
219 | // Limit to events that have no grandparent or whose grandparent has already been executed |
||
220 | $grandparentQb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
221 | $grandparentQb->select('null') |
||
222 | ->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'grandparent_log') |
||
223 | ->where( |
||
224 | $grandparentQb->expr()->eq('grandparent_log.event_id', ':grandparentId'), |
||
225 | $grandparentQb->expr()->eq('grandparent_log.lead_id', 'l.lead_id'), |
||
226 | $grandparentQb->expr()->eq('grandparent_log.rotation', 'l.rotation') |
||
227 | ); |
||
228 | $q->setParameter('grandparentId', (int) $parentDecisionId); |
||
229 | |||
230 | $q->andWhere( |
||
231 | sprintf('EXISTS (%s)', $grandparentQb->getSQL()) |
||
232 | ); |
||
233 | } |
||
234 | |||
235 | if ($limiter->hasCampaignLimit() && $limiter->getCampaignLimitRemaining() < $limiter->getBatchLimit()) { |
||
236 | $q->setMaxResults($limiter->getCampaignLimitRemaining()); |
||
237 | } |
||
238 | |||
239 | $results = $q->execute()->fetchAll(); |
||
240 | $contacts = []; |
||
241 | foreach ($results as $result) { |
||
242 | $contacts[$result['lead_id']] = new \DateTime($result['date_added'], new \DateTimeZone('UTC')); |
||
243 | } |
||
244 | |||
245 | if ($limiter->hasCampaignLimit()) { |
||
246 | $limiter->reduceCampaignLimitRemaining(count($contacts)); |
||
247 | } |
||
248 | |||
249 | return $contacts; |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * This is approximate because the query that fetches contacts per decision is based on if the grandparent has been executed or not. |
||
254 | * |
||
255 | * @return int |
||
256 | */ |
||
257 | public function getInactiveContactCount($campaignId, array $decisionIds, ContactLimiter $limiter) |
||
258 | { |
||
259 | // We have to loop over each decision to get a count or else any contact that has executed any single one of the decision IDs |
||
260 | // will not be included potentially resulting in not having the inactive path analyzed |
||
261 | |||
262 | $totalCount = 0; |
||
263 | |||
264 | foreach ($decisionIds as $decisionId) { |
||
265 | // Main query |
||
266 | $q = $this->getSlaveConnection()->createQueryBuilder(); |
||
267 | $q->select('count(*)') |
||
268 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'l') |
||
269 | ->where( |
||
270 | $q->expr()->andX( |
||
271 | $q->expr()->eq('l.campaign_id', ':campaignId'), |
||
272 | $q->expr()->eq('l.manually_removed', 0) |
||
273 | ) |
||
274 | ) |
||
275 | // Order by ID so we can query by greater than X contact ID when batching |
||
276 | ->orderBy('l.lead_id') |
||
277 | ->setParameter('campaignId', (int) $campaignId); |
||
278 | |||
279 | // Contact IDs |
||
280 | $this->updateQueryFromContactLimiter('l', $q, $limiter, true); |
||
281 | |||
282 | // Limit to events that have not been executed or scheduled yet |
||
283 | $eventQb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
284 | $eventQb->select('null') |
||
285 | ->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'log') |
||
286 | ->where( |
||
287 | $eventQb->expr()->andX( |
||
288 | $eventQb->expr()->eq('log.event_id', $decisionId), |
||
289 | $eventQb->expr()->eq('log.lead_id', 'l.lead_id'), |
||
290 | $eventQb->expr()->eq('log.rotation', 'l.rotation') |
||
291 | ) |
||
292 | ); |
||
293 | $q->andWhere( |
||
294 | sprintf('NOT EXISTS (%s)', $eventQb->getSQL()) |
||
295 | ); |
||
296 | |||
297 | $totalCount += (int) $q->execute()->fetchColumn(); |
||
298 | } |
||
299 | |||
300 | return $totalCount; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * @return array |
||
305 | */ |
||
306 | public function getCampaignMembers(array $contactIds, Campaign $campaign) |
||
307 | { |
||
308 | $qb = $this->createQueryBuilder('l'); |
||
309 | |||
310 | $qb->where( |
||
311 | $qb->expr()->andX( |
||
312 | $qb->expr()->eq('l.campaign', ':campaign'), |
||
313 | $qb->expr()->in('IDENTITY(l.lead)', ':contactIds') |
||
314 | ) |
||
315 | ) |
||
316 | ->setParameter('campaign', $campaign) |
||
317 | ->setParameter('contactIds', $contactIds, Connection::PARAM_INT_ARRAY); |
||
318 | |||
319 | $results = $qb->getQuery()->getResult(); |
||
320 | |||
321 | $campaignMembers = []; |
||
322 | |||
323 | /** @var Lead $result */ |
||
324 | foreach ($results as $result) { |
||
325 | $campaignMembers[$result->getLead()->getId()] = $result; |
||
326 | } |
||
327 | |||
328 | return $campaignMembers; |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * @param $campaignId |
||
333 | * |
||
334 | * @return array |
||
335 | */ |
||
336 | public function getContactRotations(array $contactIds, $campaignId) |
||
337 | { |
||
338 | $qb = $this->getEntityManager()->getConnection()->createQueryBuilder(); |
||
339 | $qb->select('cl.lead_id, cl.rotation') |
||
340 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
341 | ->where( |
||
342 | $qb->expr()->andX( |
||
343 | $qb->expr()->eq('cl.campaign_id', ':campaignId'), |
||
344 | $qb->expr()->in('cl.lead_id', ':contactIds') |
||
345 | ) |
||
346 | ) |
||
347 | ->setParameter('campaignId', (int) $campaignId) |
||
348 | ->setParameter('contactIds', $contactIds, Connection::PARAM_INT_ARRAY); |
||
349 | |||
350 | $results = $qb->execute()->fetchAll(); |
||
351 | |||
352 | $contactRotations = []; |
||
353 | foreach ($results as $result) { |
||
354 | $contactRotations[$result['lead_id']] = $result['rotation']; |
||
355 | } |
||
356 | |||
357 | return $contactRotations; |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * @param $campaignId |
||
362 | * @param bool $campaignCanBeRestarted |
||
363 | * |
||
364 | * @return CountResult |
||
365 | */ |
||
366 | public function getCountsForCampaignContactsBySegment($campaignId, ContactLimiter $limiter, $campaignCanBeRestarted = false) |
||
367 | { |
||
368 | if (!$segments = $this->getCampaignSegments($campaignId)) { |
||
369 | return new CountResult(0, 0, 0); |
||
370 | } |
||
371 | |||
372 | $qb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
373 | $qb->select('min(ll.lead_id) as min_id, max(ll.lead_id) as max_id, count(distinct(ll.lead_id)) as the_count') |
||
374 | ->from(MAUTIC_TABLE_PREFIX.'lead_lists_leads', 'll') |
||
375 | ->where( |
||
376 | $qb->expr()->andX( |
||
377 | $qb->expr()->eq('ll.manually_removed', 0), |
||
378 | $qb->expr()->in('ll.leadlist_id', $segments) |
||
379 | ) |
||
380 | ); |
||
381 | |||
382 | $this->updateQueryFromContactLimiter('ll', $qb, $limiter, true); |
||
383 | $this->updateQueryWithExistingMembershipExclusion($campaignId, $qb, $campaignCanBeRestarted); |
||
384 | |||
385 | if (!$campaignCanBeRestarted) { |
||
386 | $this->updateQueryWithHistoryExclusion($campaignId, $qb); |
||
387 | } |
||
388 | |||
389 | $result = $qb->execute()->fetch(); |
||
390 | |||
391 | return new CountResult($result['the_count'], $result['min_id'], $result['max_id']); |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * @param $campaignId |
||
396 | * @param bool $campaignCanBeRestarted |
||
397 | * |
||
398 | * @return array |
||
399 | */ |
||
400 | public function getCampaignContactsBySegments($campaignId, ContactLimiter $limiter, $campaignCanBeRestarted = false) |
||
401 | { |
||
402 | if (!$segments = $this->getCampaignSegments($campaignId)) { |
||
403 | return []; |
||
404 | } |
||
405 | |||
406 | $qb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
407 | $qb->select('distinct(ll.lead_id) as id') |
||
408 | ->from(MAUTIC_TABLE_PREFIX.'lead_lists_leads', 'll') |
||
409 | ->where( |
||
410 | $qb->expr()->andX( |
||
411 | $qb->expr()->eq('ll.manually_removed', 0), |
||
412 | $qb->expr()->in('ll.leadlist_id', $segments) |
||
413 | ) |
||
414 | ); |
||
415 | |||
416 | $this->updateQueryFromContactLimiter('ll', $qb, $limiter); |
||
417 | $this->updateQueryWithExistingMembershipExclusion($campaignId, $qb, $campaignCanBeRestarted); |
||
418 | |||
419 | if (!$campaignCanBeRestarted) { |
||
420 | $this->updateQueryWithHistoryExclusion($campaignId, $qb); |
||
421 | } |
||
422 | |||
423 | $results = $qb->execute()->fetchAll(); |
||
424 | |||
425 | $contacts = []; |
||
426 | foreach ($results as $result) { |
||
427 | $contacts[$result['id']] = $result['id']; |
||
428 | } |
||
429 | |||
430 | return $contacts; |
||
431 | } |
||
432 | |||
433 | /** |
||
434 | * @param $campaignId |
||
435 | * |
||
436 | * @return int |
||
437 | */ |
||
438 | public function getCountsForOrphanedContactsBySegments($campaignId, ContactLimiter $limiter) |
||
439 | { |
||
440 | $segments = $this->getCampaignSegments($campaignId); |
||
441 | |||
442 | $qb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
443 | $qb->select('min(cl.lead_id) as min_id, max(cl.lead_id) as max_id, count(cl.lead_id) as the_count') |
||
444 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
445 | ->where( |
||
446 | $qb->expr()->andX( |
||
447 | $qb->expr()->eq('cl.campaign_id', (int) $campaignId), |
||
448 | $qb->expr()->eq('cl.manually_removed', 0), |
||
449 | $qb->expr()->eq('cl.manually_added', 0) |
||
450 | ) |
||
451 | ); |
||
452 | |||
453 | $this->updateQueryFromContactLimiter('cl', $qb, $limiter, true); |
||
454 | $this->updateQueryWithSegmentMembershipExclusion($segments, $qb); |
||
455 | |||
456 | $result = $qb->execute()->fetch(); |
||
457 | |||
458 | return new CountResult($result['the_count'], $result['min_id'], $result['max_id']); |
||
459 | } |
||
460 | |||
461 | /** |
||
462 | * @param $campaignId |
||
463 | * |
||
464 | * @return array |
||
465 | */ |
||
466 | public function getOrphanedContacts($campaignId, ContactLimiter $limiter) |
||
467 | { |
||
468 | $segments = $this->getCampaignSegments($campaignId); |
||
469 | |||
470 | $qb = $this->getSlaveConnection($limiter)->createQueryBuilder(); |
||
471 | $qb->select('cl.lead_id as id') |
||
472 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
473 | ->where( |
||
474 | $qb->expr()->andX( |
||
475 | $qb->expr()->eq('cl.campaign_id', (int) $campaignId), |
||
476 | $qb->expr()->eq('cl.manually_removed', 0), |
||
477 | $qb->expr()->eq('cl.manually_added', 0) |
||
478 | ) |
||
479 | ); |
||
480 | |||
481 | $this->updateQueryFromContactLimiter('cl', $qb, $limiter, false); |
||
482 | $this->updateQueryWithSegmentMembershipExclusion($segments, $qb); |
||
483 | |||
484 | $results = $qb->execute()->fetchAll(); |
||
485 | |||
486 | $contacts = []; |
||
487 | foreach ($results as $result) { |
||
488 | $contacts[$result['id']] = $result['id']; |
||
489 | } |
||
490 | |||
491 | return $contacts; |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * Takes an array of contact ID's and increments |
||
496 | * their current rotation in a campaign by 1. |
||
497 | * |
||
498 | * @param int $campaignId |
||
499 | * |
||
500 | * @return bool |
||
501 | */ |
||
502 | public function incrementCampaignRotationForContacts(array $contactIds, $campaignId) |
||
503 | { |
||
504 | $q = $this->getEntityManager()->getConnection()->createQueryBuilder(); |
||
505 | |||
506 | $q->update(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
507 | ->set('cl.rotation', 'cl.rotation + 1') |
||
508 | ->where( |
||
509 | $q->expr()->andX( |
||
510 | $q->expr()->in('cl.lead_id', ':contactIds'), |
||
511 | $q->expr()->eq('cl.campaign_id', ':campaignId') |
||
512 | ) |
||
513 | ) |
||
514 | ->setParameter('contactIds', $contactIds, Connection::PARAM_INT_ARRAY) |
||
515 | ->setParameter('campaignId', (int) $campaignId) |
||
516 | ->execute(); |
||
517 | } |
||
518 | |||
519 | /** |
||
520 | * @param $campaignId |
||
521 | * |
||
522 | * @return array |
||
523 | */ |
||
524 | private function getCampaignSegments($campaignId) |
||
525 | { |
||
526 | // Get published segments for this campaign |
||
527 | $segmentResults = $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
528 | ->select('cl.leadlist_id') |
||
529 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leadlist_xref', 'cl') |
||
530 | ->join('cl', MAUTIC_TABLE_PREFIX.'lead_lists', 'll', 'll.id = cl.leadlist_id and ll.is_published = 1') |
||
531 | ->where('cl.campaign_id = '.(int) $campaignId) |
||
532 | ->execute() |
||
533 | ->fetchAll(); |
||
534 | |||
535 | if (empty($segmentResults)) { |
||
536 | // No segments so no contacts |
||
537 | return []; |
||
538 | } |
||
539 | |||
540 | $segments = []; |
||
541 | foreach ($segmentResults as $result) { |
||
542 | $segments[] = $result['leadlist_id']; |
||
543 | } |
||
544 | |||
545 | return $segments; |
||
546 | } |
||
547 | |||
548 | /** |
||
549 | * @param $campaignId |
||
550 | */ |
||
551 | private function updateQueryWithExistingMembershipExclusion($campaignId, QueryBuilder $qb, $campaignCanBeRestarted = false) |
||
552 | { |
||
553 | $membershipConditions = [ |
||
554 | $qb->expr()->eq('cl.lead_id', 'll.lead_id'), |
||
555 | $qb->expr()->eq('cl.campaign_id', (int) $campaignId), |
||
556 | ]; |
||
557 | |||
558 | if ($campaignCanBeRestarted) { |
||
559 | $membershipConditions[] = $qb->expr()->eq('cl.manually_removed', 0); |
||
560 | } |
||
561 | |||
562 | $subq = $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
563 | ->select('null') |
||
564 | ->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl') |
||
565 | ->where( |
||
566 | $qb->expr()->andX(...$membershipConditions) |
||
567 | ); |
||
568 | |||
569 | $qb->andWhere( |
||
570 | sprintf('NOT EXISTS (%s)', $subq->getSQL()) |
||
571 | ); |
||
572 | } |
||
573 | |||
574 | private function updateQueryWithSegmentMembershipExclusion(array $segments, QueryBuilder $qb) |
||
575 | { |
||
576 | if (0 === count($segments)) { |
||
577 | // No segments so nothing to exclude |
||
578 | return; |
||
579 | } |
||
580 | |||
581 | $subq = $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
582 | ->select('null') |
||
583 | ->from(MAUTIC_TABLE_PREFIX.'lead_lists_leads', 'll') |
||
584 | ->where( |
||
585 | $qb->expr()->andX( |
||
586 | $qb->expr()->eq('ll.lead_id', 'cl.lead_id'), |
||
587 | $qb->expr()->eq('ll.manually_removed', 0), |
||
588 | $qb->expr()->in('ll.leadlist_id', $segments) |
||
589 | ) |
||
590 | ); |
||
591 | |||
592 | $qb->andWhere( |
||
593 | sprintf('NOT EXISTS (%s)', $subq->getSQL()) |
||
594 | ); |
||
595 | } |
||
596 | |||
597 | /** |
||
598 | * Exclude contacts with any previous campaign history; this is mainly BC for pre 2.14.0 where the membership entry was deleted. |
||
599 | * |
||
600 | * @param $campaignId |
||
601 | */ |
||
602 | private function updateQueryWithHistoryExclusion($campaignId, QueryBuilder $qb) |
||
603 | { |
||
604 | $subq = $this->getEntityManager()->getConnection()->createQueryBuilder() |
||
605 | ->select('null') |
||
606 | ->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'el') |
||
607 | ->where( |
||
608 | $qb->expr()->andX( |
||
609 | $qb->expr()->eq('el.lead_id', 'll.lead_id'), |
||
610 | $qb->expr()->eq('el.campaign_id', (int) $campaignId) |
||
611 | ) |
||
612 | ); |
||
613 | |||
614 | $qb->andWhere( |
||
615 | sprintf('NOT EXISTS (%s)', $subq->getSQL()) |
||
616 | ); |
||
617 | } |
||
618 | } |
||
619 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.