Completed
Push — master ( 978f4c...209464 )
by Stepan
129:29 queued 124:29
created

AnalyticsService   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 15
eloc 84
dl 0
loc 199
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getDailyTicketsSoldData() 0 45 3
A __construct() 0 3 1
A getLastDayOfTicketSales() 0 3 2
B getDataForCompareTicketSales() 0 45 7
A getSummaryTicketsSoldData() 0 26 1
A getFirstDayOfTicketSales() 0 17 1
1
<?php
2
3
namespace Application\Bundle\DefaultBundle\Service;
4
5
use Stfalcon\Bundle\EventBundle\Entity\Event;
6
use Stfalcon\Bundle\EventBundle\Entity\Payment;
7
use Doctrine\ORM\EntityManager;
8
9
/**
10
 * Service to get sales analytics data
11
 */
12
class AnalyticsService
13
{
14
    /** @var EntityManager */
15
    protected $em;
16
17
    /**
18
     * @param EntityManager $em
19
     */
20
    public function __construct($em)
21
    {
22
        $this->em = $em;
23
    }
24
25
    /**
26
     * Get data for daily statistics of tickets sold
27
     *
28
     * @param Event $event
29
     *
30
     * @throws \Exception
31
     *
32
     * @return array
33
     */
34
    public function getDailyTicketsSoldData(Event $event)
35
    {
36
        $dateFrom = $this->getFirstDayOfTicketSales($event);
37
        $dateTo = $this->getLastDayOfTicketSales($event);
38
39
        $qb = $this->em->createQueryBuilder();
40
        $qb->select('DATE(p.updatedAt) as date_of_sale, COUNT(t.id) as tickets_sold_number')
41
            ->from('Stfalcon\Bundle\EventBundle\Entity\Ticket', 't')
42
            ->join('t.payment', 'p')
43
            ->where($qb->expr()->eq('t.event', ':event'))
44
            ->andWhere($qb->expr()->gte('p.updatedAt', ':date_from'))
45
            ->andWhere($qb->expr()->lte('p.updatedAt', ':date_to'))
46
            ->andWhere($qb->expr()->eq('p.status', ':status'))
47
            ->andWhere('p.amount > 0') // тільки реально продані квитки
48
            ->setParameters([
49
                'event' => $event,
50
                'date_from' => $dateFrom,
51
                'date_to' => $dateTo,
52
                'status' => Payment::STATUS_PAID,
53
            ])
54
            ->addGroupBy('date_of_sale')
55
        ;
56
57
        $results = $qb
58
            ->getQuery()
59
            ->getResult()
60
        ;
61
62
        // fill the possible gap in sequence of dates
63
        $dateRange = new \DatePeriod($dateFrom, new \DateInterval('P1D'), $dateTo->modify('+1 day'));
64
65
        $formattedResult = [];
66
        foreach ($dateRange as $date) {
67
            /* @var $date \DateTime */
68
            $key = $date->format('Y-m-d');
69
            $formattedResult[$key][0] = $date;
70
            $formattedResult[$key][1] = null;
71
        }
72
73
        // merge real data with array of prepared results
74
        foreach ($results as $result) {
75
            $formattedResult[$result['date_of_sale']][1] = (int) $result['tickets_sold_number'];
76
        }
77
78
        return $formattedResult;
79
    }
80
81
82
    /**
83
     * Get data for summary statistics of tickets sold
84
     *
85
     * @param Event|null $event
86
     *
87
     * @throws \Exception
88
     * @return array
89
     */
90
    public function getSummaryTicketsSoldData(Event $event)
91
    {
92
        $qbTicketsSold = $this->em->createQueryBuilder();
93
        $qbTicketsSold->select('COUNT(t.id) as tickets_sold_number, SUM(t.amount) as tickets_amount')
94
            ->from('Stfalcon\Bundle\EventBundle\Entity\Ticket', 't')
95
            ->join('t.payment', 'p')
96
            ->andWhere($qbTicketsSold->expr()->eq('t.event', ':event'))
97
            ->andWhere($qbTicketsSold->expr()->eq('p.status', ':status'))
98
            ->setParameters([
99
                'event' => $event,
100
                'status' => Payment::STATUS_PAID,
101
            ])
102
        ;
103
104
        $qbFreeTickets = clone $qbTicketsSold;
105
106
        $qbTicketsSold->andWhere('p.amount > 0');
107
        $results = $qbTicketsSold->getQuery()->getSingleResult();
108
109
        $qbFreeTickets->andWhere('p.amount = 0'); //free_tickets_number
110
        $resultsFreeTickets = $qbFreeTickets->getQuery()->getSingleResult();
111
112
        $results['free_tickets_number'] = $resultsFreeTickets['tickets_sold_number'];
113
        $results['total_tickets_number'] = $results['free_tickets_number'] + $results['tickets_sold_number'];
114
115
        return $results;
116
    }
117
    /**
118
     * Get data for compare ticket sales (with previous events)
119
     *
120
     * @param Event $event
121
     *
122
     * @throws \Exception
123
     *
124
     * @return array
125
     */
126
    public function getDataForCompareTicketSales(Event $event)
127
    {
128
        $weeksMaxNumber = 20; // задаєм максимальну глибину аналізу
129
130
        // витягнути івенти з цієї групи
131
        $events = $this->em->getRepository('StfalconEventBundle:Event')
132
            ->findBy(['group' => $event->getGroup()], ['date' => 'DESC'], 4);
133
134
        // формуєм масив ключів з айдшок івентів, щоб використати його в формуванні заготовки масиву результатів
135
        $resultsKeys = [$event->getId()];
136
        foreach ($events as $e) {
137
            /* @var $e Event */
138
            $resultsKeys[] = $e->getId();
139
        }
140
        $resultsValueTemplate = array_fill_keys($resultsKeys, null);
141
        // заповнюєм заготовку масиву результатів
142
        $results = array_fill(0, $weeksMaxNumber, $resultsValueTemplate);
143
144
        // витягуєм статистику продажів для івентів з цієї групи
145
        foreach ($events as $e) {
146
            /* @var $e Event */
147
            $dataForDailyStatistics = $this->getDailyTicketsSoldData($e);
148
            $reverseDataForDailyStatistics = array_reverse($dataForDailyStatistics);
149
150
            // групуєм статистику продажів для івенту по тижнях
151
            $oneEventResults = [];
152
            foreach ($reverseDataForDailyStatistics as $oneDateData) {
153
                /* @var $date \DateTime */
154
                $date = $oneDateData[0];
155
                $number = $oneDateData[1];
156
157
                $key = $date->format("Y-W");
158
                $oneEventResults[$key] = (isset($oneEventResults[$key]) ? $oneEventResults[$key] : 0) + $number;
159
            }
160
161
            // мержим отриману статистику івента в загальний масив результатів
162
            foreach (array_values($oneEventResults) as $week => $number) {
163
                if ($week == $weeksMaxNumber) {
164
                    break;
165
                }
166
                $results[$week][$e->getId()] = $number;
167
            }
168
        }
169
170
        return array_reverse($results);
171
    }
172
173
    /**
174
     * Get the first day of ticket sales (get createdAt of the first event ticket)
175
     *
176
     * @param Event $event
177
     *
178
     * @throws \Doctrine\ORM\Query\QueryException
179
     *
180
     * @return \DateTime
181
     */
182
    private function getFirstDayOfTicketSales(Event $event)
183
    {
184
        $qb = $this->em->createQueryBuilder();
185
        $qb->select('t.createdAt')
186
            ->from('Stfalcon\Bundle\EventBundle\Entity\Ticket', 't')
187
            ->where($qb->expr()->eq('t.event', ':event'))
188
            ->andWhere($qb->expr()->eq('t.event', ':event'))
189
            ->setParameters([
190
                'event' => $event,
191
            ])
192
            ->orderBy('t.createdAt', 'ASC')
193
            ->setMaxResults(1);
194
195
        $date = $qb->getQuery()
196
            ->getSingleScalarResult();
197
198
        return new \DateTime($date);
199
    }
200
201
    /**
202
     * Get the last day of ticket sales
203
     *
204
     * @param Event $event
205
     *
206
     * @return \DateTime|null
207
     */
208
    private function getLastDayOfTicketSales(Event $event)
209
    {
210
        return $event->getDateEnd() ?: $event->getDate();
211
    }
212
}
213