Completed
Push — master ( 584969...3f5763 )
by
unknown
11:30
created

LeadRepository::sortByCountReverse()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 13
rs 9.4285
cc 3
eloc 7
nc 1
nop 1
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $owners of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
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 = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $owners of type integer[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
185
            QueryUtils::applyOptimizedIn($qb, 'l.owner', $owners);
186
        }
187
188
        return $qb;
189
    }
190
}
191