Test Failed
Pull Request — master (#228)
by Guilherme
03:49
created

SmsStatusService::updateSentVerificationStatus()   B

Complexity

Conditions 8
Paths 17

Size

Total Lines 55
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 39
nc 17
nop 1
dl 0
loc 55
rs 7.4033
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the login-cidadao project or it's bundles.
4
 *
5
 * (c) Guilherme Donato <guilhermednt on github>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LoginCidadao\PhoneVerificationBundle\Service;
12
13
use Doctrine\ORM\EntityManagerInterface;
14
use LoginCidadao\PhoneVerificationBundle\Entity\SentVerificationRepository;
15
use LoginCidadao\PhoneVerificationBundle\Event\UpdateStatusEvent;
16
use LoginCidadao\PhoneVerificationBundle\Model\SentVerificationInterface;
17
use LoginCidadao\PhoneVerificationBundle\Model\SmsStatusInterface;
18
use LoginCidadao\PhoneVerificationBundle\PhoneVerificationEvents;
19
use Symfony\Component\Console\Style\SymfonyStyle;
20
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21
22
class SmsStatusService
23
{
24
    /** @var EntityManagerInterface */
25
    private $em;
26
27
    /** @var EventDispatcherInterface */
28
    private $dispatcher;
29
30
    /** @var SentVerificationRepository */
31
    private $sentVerificationRepo;
32
33
    /** @var SymfonyStyle */
34
    private $io;
35
36
    /**
37
     * SmsStatusUpdater constructor.
38
     * @param EntityManagerInterface $em
39
     * @param EventDispatcherInterface $dispatcher
40
     * @param SentVerificationRepository $sentVerificationRepo
41
     */
42
    public function __construct(
43
        EntityManagerInterface $em,
44
        EventDispatcherInterface $dispatcher,
45
        SentVerificationRepository $sentVerificationRepo
46
    ) {
47
        $this->em = $em;
48
        $this->dispatcher = $dispatcher;
49
        $this->sentVerificationRepo = $sentVerificationRepo;
50
    }
51
52
    /**
53
     * @param SymfonyStyle $io
54
     * @return SmsStatusService
55
     */
56
    public function setSymfonyStyle(SymfonyStyle $io)
57
    {
58
        $this->io = $io;
59
60
        return $this;
61
    }
62
63
    /**
64
     * @param $transactionId
65
     * @return SmsStatusInterface
66
     */
67
    public function getSmsStatus($transactionId)
68
    {
69
        $event = $this->getStatus($transactionId);
70
71
        return $event->getDeliveryStatus();
72
    }
73
74
    public function updateSentVerificationStatus($batchSize = 1)
75
    {
76
        $count = $this->sentVerificationRepo->countPendingUpdateSentVerification();
77
78
        if ($count === 0) {
79
            $this->comment('No messages pending update.');
80
81
            return [];
82
        }
83
84
        $query = $this->sentVerificationRepo->getPendingUpdateSentVerificationQuery();
85
        $sentVerifications = $query->iterate();
86
87
        $this->em->getConnection() ? $this->em->getConnection()->getConfiguration()->setSQLLogger(null) : null;
88
        gc_enable();
89
        $this->progressStart($count);
90
        $transactionsUpdated = [];
91
        foreach ($sentVerifications as $row) {
92
            /** @var SentVerificationInterface $sentVerification */
93
            $sentVerification = $row[0];
94
            $event = $this->getStatus($sentVerification->getTransactionId());
95
            if (false === $event->isUpdated()) {
96
                $this->progressAdvance(1);
97
                unset($event);
98
                unset($sentVerification);
99
                gc_collect_cycles();
100
                continue;
101
            }
102
103
            $deliveredAt = $event->getDeliveredAt();
104
            $sentVerification->setActuallySentAt($event->getSentAt())
105
                ->setDeliveredAt($deliveredAt)
106
                ->setFinished($deliveredAt instanceof \DateTime || $event->getDeliveryStatus()->isFinal());
107
            $transactionsUpdated[] = $sentVerification->getTransactionId();
108
            unset($event);
109
            unset($sentVerification);
110
            if ((count($transactionsUpdated) % $batchSize) === 0) {
111
                $this->em->flush();
112
                $this->em->clear();
113
                gc_collect_cycles();
114
            }
115
            $this->progressAdvance(1);
116
        }
117
        $this->em->flush();
118
        $this->em->clear();
119
        $this->progressFinish();
120
121
        $countUpdated = count($transactionsUpdated);
122
        $this->comment("Updated {$countUpdated} transactions.");
123
124
        if ($countUpdated === 0) {
125
            $this->comment("It's possible the SMS-sending service you are using doesn't implement status updates.");
126
        }
127
128
        return $transactionsUpdated;
129
    }
130
131
    /**
132
     * @param $amount
133
     * @return float average delivery time in seconds (abs value)
134
     */
135
    public function getAverageDeliveryTime($amount)
136
    {
137
        /** @var SentVerificationInterface[] $sentVerifications */
138
        $sentVerifications = $this->sentVerificationRepo->getLastDeliveredVerifications($amount);
139
140
        if (count($sentVerifications) === 0) {
141
            return 0;
142
        }
143
144
        $times = [];
145
        foreach ($sentVerifications as $sentVerification) {
146
            $times[] = abs(
147
                $sentVerification->getDeliveredAt()->format('U') - $sentVerification->getSentAt()->format('U')
148
            );
149
        }
150
        $sum = array_sum($times);
151
152
        $avg = $sum / count($times);
153
154
        return $avg;
155
    }
156
157
    /**
158
     * @param int $maxDeliverySeconds
159
     * @return array
160
     */
161
    public function getDelayedDeliveryTransactions($maxDeliverySeconds = 0)
162
    {
163
        $date = new \DateTime("-{$maxDeliverySeconds} seconds");
164
        $notDelivered = $this->sentVerificationRepo->getNotDeliveredSince($date);
165
166
        $transactions = [];
167
        foreach ($notDelivered as $sentVerification) {
168
            $transactions[] = [
169
                'transaction_id' => $sentVerification->getTransactionId(),
170
                'sent_at' => $sentVerification->getSentAt()->format('c'),
171
            ];
172
        }
173
174
        return $transactions;
175
    }
176
177
    /**
178
     * @param $transactionId
179
     * @return UpdateStatusEvent
180
     */
181
    private function getStatus($transactionId)
182
    {
183
        $event = new UpdateStatusEvent($transactionId);
184
        $this->dispatcher->dispatch(PhoneVerificationEvents::PHONE_VERIFICATION_GET_SENT_VERIFICATION_STATUS, $event);
185
186
        return $event;
187
    }
188
189
    private function comment($message)
190
    {
191
        if (!$this->io) {
192
            return;
193
        }
194
        $this->io->comment($message);
195
    }
196
197
    private function progressStart($max = 0)
198
    {
199
        if (!$this->io) {
200
            return;
201
        }
202
        $this->io->progressStart($max);
203
    }
204
205
    private function progressAdvance($step = 1)
206
    {
207
        if (!$this->io) {
208
            return;
209
        }
210
        $this->io->progressAdvance($step);
211
    }
212
213
    private function progressFinish()
214
    {
215
        if (!$this->io) {
216
            return;
217
        }
218
        $this->io->progressFinish();
219
    }
220
}
221