Completed
Pull Request — master (#502)
by Stepan
04:45
created

AnalyticsService::getLastDayOfTicketSales()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 2
nc 1
nop 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
89
     * @return array
90
     */
91
    public function getSummaryTicketsSoldData(Event $event)
92
    {
93
        $qbTicketsSold = $this->em->createQueryBuilder();
94
        $qbTicketsSold->select('COUNT(t.id) as tickets_sold_number, SUM(t.amount) as tickets_amount')
95
            ->from('Stfalcon\Bundle\EventBundle\Entity\Ticket', 't')
96
            ->join('t.payment', 'p')
97
            ->andWhere($qbTicketsSold->expr()->eq('t.event', ':event'))
98
            ->andWhere($qbTicketsSold->expr()->eq('p.status', ':status'))
99
            ->setParameters([
100
                'event' => $event,
101
                'status' => Payment::STATUS_PAID,
102
            ])
103
        ;
104
105
        $qbFreeTickets = clone $qbTicketsSold;
106
107
        $qbTicketsSold->andWhere('p.amount > 0');
108
        $results = $qbTicketsSold->getQuery()->getSingleResult();
109
110
        $qbFreeTickets->andWhere('p.amount = 0'); //free_tickets_number
111
        $resultsFreeTickets = $qbFreeTickets->getQuery()->getSingleResult();
112
113
        $results['free_tickets_number'] = $resultsFreeTickets['tickets_sold_number'];
114
        $results['total_tickets_number'] = $results['free_tickets_number'] + $results['tickets_sold_number'];
115
116
        return $results;
117
    }
118
    /**
119
     * Get data for compare ticket sales (with previous events)
120
     *
121
     * @param Event $event
122
     *
123
     * @throws \Exception
124
     *
125
     * @return array
126
     */
127
    public function getDataForCompareTicketSales(Event $event)
128
    {
129
        $weeksMaxNumber = 20; // задаєм максимальну глибину аналізу
130
131
        // витягнути івенти з цієї групи
132
        $events = $this->em->getRepository('StfalconEventBundle:Event')
133
            ->findBy(['group' => $event->getGroup()], ['date' => 'DESC'], 4);
134
135
        // формуєм масив ключів з айдшок івентів, щоб використати його в формуванні заготовки масиву результатів
136
        $resultsKeys = [$event->getId()];
137
        foreach ($events as $e) {
138
            /* @var $e Event */
139
            $resultsKeys[] = $e->getId();
140
        }
141
        $resultsValueTemplate = array_fill_keys($resultsKeys, null);
142
        // заповнюєм заготовку масиву результатів
143
        $results = array_fill(0, $weeksMaxNumber, $resultsValueTemplate);
144
145
        // витягуєм статистику продажів для івентів з цієї групи
146
        foreach ($events as $e) {
147
            /* @var $e Event */
148
            $dataForDailyStatistics = $this->getDailyTicketsSoldData($e);
149
            $reverseDataForDailyStatistics = array_reverse($dataForDailyStatistics);
150
151
            // групуєм статистику продажів для івенту по тижнях
152
            $oneEventResults = [];
153
            foreach ($reverseDataForDailyStatistics as $oneDateData) {
154
                /* @var $date \DateTime */
155
                $date = $oneDateData[0];
156
                $number = $oneDateData[1];
157
158
                $key = $date->format("Y-W");
159
                $oneEventResults[$key] = (isset($oneEventResults[$key]) ? $oneEventResults[$key] : 0) + $number;
160
            }
161
162
            // мержим отриману статистику івента в загальний масив результатів
163
            foreach (array_values($oneEventResults) as $week => $number) {
164
                if ($week == $weeksMaxNumber) {
165
                    break;
166
                }
167
                $results[$week][$e->getId()] = $number;
168
            }
169
        }
170
171
        return array_reverse($results);
172
    }
173
174
    /**
175
     * Get the first day of ticket sales (get createdAt of the first event ticket)
176
     *
177
     * @param Event $event
178
     *
179
     * @throws \Doctrine\ORM\Query\QueryException
180
     *
181
     * @return \DateTime
182
     */
183
    private function getFirstDayOfTicketSales(Event $event)
184
    {
185
        $qb = $this->em->createQueryBuilder();
186
        $qb->select('t.createdAt')
187
            ->from('Stfalcon\Bundle\EventBundle\Entity\Ticket', 't')
188
            ->where($qb->expr()->eq('t.event', ':event'))
189
            ->andWhere($qb->expr()->eq('t.event', ':event'))
190
            ->setParameters([
191
                'event' => $event,
192
            ])
193
            ->orderBy('t.createdAt', 'ASC')
194
            ->setMaxResults(1);
195
196
        $date = $qb->getQuery()
197
            ->getSingleScalarResult();
198
199
        return new \DateTime($date);
200
    }
201
202
    /**
203
     * Get the last day of ticket sales
204
     *
205
     * @param Event $event
206
     *
207
     * @return \DateTime|null
208
     */
209
    private function getLastDayOfTicketSales(Event $event)
210
    {
211
        return $event->getDateEnd() ?: $event->getDate();
212
    }
213
}
214