1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Oro\Bundle\SalesBundle\Entity\Repository; |
4
|
|
|
|
5
|
|
|
use Doctrine\ORM\EntityRepository; |
6
|
|
|
use Doctrine\ORM\QueryBuilder; |
7
|
|
|
|
8
|
|
|
use Oro\Component\DoctrineUtils\ORM\QueryUtils; |
9
|
|
|
use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper; |
10
|
|
|
|
11
|
|
|
class LeadRepository extends EntityRepository |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Returns top $limit opportunities grouped by lead source |
15
|
|
|
* |
16
|
|
|
* @deprecated since 1.10. Use OpportunityRepository::getOpportunitiesCountGroupByLeadSource instead |
17
|
|
|
* @see OpportunityRepository::getOpportunitiesCountGroupByLeadSource |
18
|
|
|
* |
19
|
|
|
* @param AclHelper $aclHelper |
20
|
|
|
* @param int $limit |
21
|
|
|
* @param array $dateRange |
22
|
|
|
* |
23
|
|
|
* @return array [itemCount, label] |
24
|
|
|
*/ |
25
|
|
|
public function getOpportunitiesByLeadSource(AclHelper $aclHelper, $limit = 10, $dateRange = null, $owners = []) |
26
|
|
|
{ |
27
|
|
|
$qb = $this->createQueryBuilder('l') |
28
|
|
|
->select('s.id as source, count(o.id) as itemCount') |
29
|
|
|
->leftJoin('l.opportunities', 'o') |
30
|
|
|
->leftJoin('l.source', 's') |
31
|
|
|
->groupBy('source'); |
32
|
|
|
|
33
|
|
|
if ($dateRange && $dateRange['start'] && $dateRange['end']) { |
34
|
|
|
$qb->andWhere($qb->expr()->between('o.createdAt', ':dateStart', ':dateEnd')) |
35
|
|
|
->setParameter('dateStart', $dateRange['start']) |
36
|
|
|
->setParameter('dateEnd', $dateRange['end']); |
37
|
|
|
} |
38
|
|
|
if ($owners) { |
|
|
|
|
39
|
|
|
QueryUtils::applyOptimizedIn($qb, 'o.owner', $owners); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
$rows = $aclHelper->apply($qb)->getArrayResult(); |
43
|
|
|
|
44
|
|
|
return $this->processOpportunitiesByLeadSource($rows, $limit); |
|
|
|
|
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @deprecated since 1.10. Used by deprecated getOpportunitiesByLeadSource |
49
|
|
|
* @see LeadRepository::getOpportunitiesByLeadSource |
50
|
|
|
* |
51
|
|
|
* @param array $rows |
52
|
|
|
* @param int $limit |
53
|
|
|
* |
54
|
|
|
* @return array |
55
|
|
|
*/ |
56
|
|
|
protected function processOpportunitiesByLeadSource(array $rows, $limit) |
57
|
|
|
{ |
58
|
|
|
$result = []; |
59
|
|
|
$unclassified = null; |
60
|
|
|
$others = []; |
61
|
|
|
|
62
|
|
|
$this->sortByCountReverse($rows); |
|
|
|
|
63
|
|
|
foreach ($rows as $row) { |
64
|
|
|
if ($row['itemCount']) { |
65
|
|
|
if ($row['source'] === null) { |
66
|
|
|
$unclassified = $row; |
67
|
|
|
} else { |
68
|
|
|
if (count($result) < $limit) { |
69
|
|
|
$result[] = $row; |
70
|
|
|
} else { |
71
|
|
|
$others[] = $row; |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
if ($unclassified) { |
78
|
|
|
if (count($result) === $limit) { |
79
|
|
|
// allocate space for 'unclassified' item |
80
|
|
|
array_unshift($others, array_pop($result)); |
81
|
|
|
} |
82
|
|
|
// add 'unclassified' item to the top to avoid moving it to $others |
83
|
|
|
array_unshift($result, $unclassified); |
84
|
|
|
} |
85
|
|
|
if (!empty($others)) { |
86
|
|
|
if (count($result) === $limit) { |
87
|
|
|
// allocate space for 'others' item |
88
|
|
|
array_unshift($others, array_pop($result)); |
89
|
|
|
} |
90
|
|
|
// add 'others' item |
91
|
|
|
$result[] = [ |
92
|
|
|
'source' => '', |
93
|
|
|
'itemCount' => $this->sumCount($others) |
|
|
|
|
94
|
|
|
]; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
return $result; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @deprecated since 1.10. Used by deprecated getOpportunitiesByLeadSource |
102
|
|
|
* @see LeadRepository::getOpportunitiesByLeadSource |
103
|
|
|
* |
104
|
|
|
* @param array $rows |
105
|
|
|
* |
106
|
|
|
* @return int |
107
|
|
|
*/ |
108
|
|
|
protected function sumCount(array $rows) |
109
|
|
|
{ |
110
|
|
|
$result = 0; |
111
|
|
|
foreach ($rows as $row) { |
112
|
|
|
$result += $row['itemCount']; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
return $result; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @deprecated since 1.10. Used by deprecated getOpportunitiesByLeadSource |
120
|
|
|
* @see LeadRepository::getOpportunitiesByLeadSource |
121
|
|
|
* |
122
|
|
|
* @param array $rows |
123
|
|
|
*/ |
124
|
|
|
protected function sortByCountReverse(array &$rows) |
125
|
|
|
{ |
126
|
|
|
usort( |
127
|
|
|
$rows, |
128
|
|
View Code Duplication |
function ($a, $b) { |
|
|
|
|
129
|
|
|
if ($a['itemCount'] === $b['itemCount']) { |
130
|
|
|
return 0; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return $a['itemCount'] < $b['itemCount'] ? 1 : -1; |
134
|
|
|
} |
135
|
|
|
); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @param AclHelper $aclHelper |
140
|
|
|
* @param \DateTime $start |
141
|
|
|
* @param \DateTime $end |
142
|
|
|
* @param int[] $owners |
143
|
|
|
* |
144
|
|
|
* @return int |
145
|
|
|
*/ |
146
|
|
|
public function getLeadsCount(AclHelper $aclHelper, \DateTime $start = null, \DateTime $end = null, $owners = []) |
147
|
|
|
{ |
148
|
|
|
$qb = $this |
149
|
|
|
->createLeadsCountQb($start, $end, $owners) |
150
|
|
|
->innerJoin('l.opportunities', 'o'); |
151
|
|
|
|
152
|
|
|
return $aclHelper->apply($qb)->getSingleScalarResult(); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @param AclHelper $aclHelper |
157
|
|
|
* @param \DateTime $start |
158
|
|
|
* @param \DateTime $end |
159
|
|
|
* @param int[] $owners |
160
|
|
|
* |
161
|
|
|
* @return int |
162
|
|
|
*/ |
163
|
|
|
public function getNewLeadsCount(AclHelper $aclHelper, \DateTime $start = null, \DateTime $end = null, $owners = []) |
164
|
|
|
{ |
165
|
|
|
$qb = $this->createLeadsCountQb($start, $end, $owners); |
166
|
|
|
|
167
|
|
|
return $aclHelper->apply($qb)->getSingleScalarResult(); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param AclHelper $aclHelper |
172
|
|
|
* @param int[] $owners |
173
|
|
|
* |
174
|
|
|
* @return int |
175
|
|
|
*/ |
176
|
|
|
public function getOpenLeadsCount(AclHelper $aclHelper, $owners = []) |
177
|
|
|
{ |
178
|
|
|
$qb = $this->createLeadsCountQb(null, null, $owners); |
179
|
|
|
$qb->andWhere( |
180
|
|
|
$qb->expr()->notIn('l.status', ['qualified', 'canceled']) |
181
|
|
|
); |
182
|
|
|
|
183
|
|
|
return $aclHelper->apply($qb)->getSingleScalarResult(); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @param \DateTime $start |
188
|
|
|
* @param \DateTime $end |
189
|
|
|
* @param int[] $owners |
190
|
|
|
* |
191
|
|
|
* @return QueryBuilder |
192
|
|
|
*/ |
193
|
|
View Code Duplication |
protected function createLeadsCountQb( |
|
|
|
|
194
|
|
|
\DateTime $start = null, |
195
|
|
|
\DateTime $end = null, |
196
|
|
|
$owners = [] |
197
|
|
|
) { |
198
|
|
|
$qb = $this |
199
|
|
|
->createQueryBuilder('l') |
200
|
|
|
->select('COUNT(DISTINCT l.id)'); |
201
|
|
|
|
202
|
|
|
if ($start) { |
203
|
|
|
$qb |
204
|
|
|
->andWhere('l.createdAt > :start') |
205
|
|
|
->setParameter('start', $start); |
206
|
|
|
} |
207
|
|
|
if ($end) { |
208
|
|
|
$qb |
209
|
|
|
->andWhere('l.createdAt < :end') |
210
|
|
|
->setParameter('end', $end); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
if ($owners) { |
|
|
|
|
214
|
|
|
QueryUtils::applyOptimizedIn($qb, 'l.owner', $owners); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
return $qb; |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.