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) |
||||
0 ignored issues
–
show
|
|||||
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
The method
getId() does not exist on Mautic\CampaignBundle\Entity\Lead .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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.
Loading history...
|
|||||
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 compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.