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