Completed
Pull Request — master (#228)
by Guilherme
04:22
created

SmsStatusService::updateSentVerificationStatus()   B

Complexity

Conditions 8
Paths 17

Size

Total Lines 55
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 8

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
ccs 40
cts 40
cp 1
crap 8

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 9
    public function __construct(
43
        EntityManagerInterface $em,
44
        EventDispatcherInterface $dispatcher,
45
        SentVerificationRepository $sentVerificationRepo
46
    ) {
47 9
        $this->em = $em;
48 9
        $this->dispatcher = $dispatcher;
49 9
        $this->sentVerificationRepo = $sentVerificationRepo;
50 9
    }
51
52
    /**
53
     * @param SymfonyStyle $io
54
     * @return SmsStatusService
55
     */
56 8
    public function setSymfonyStyle(SymfonyStyle $io)
57
    {
58 8
        $this->io = $io;
59
60 8
        return $this;
61
    }
62
63
    /**
64
     * @param $transactionId
65
     * @return SmsStatusInterface
66
     */
67 1
    public function getSmsStatus($transactionId)
68
    {
69 1
        $event = $this->getStatus($transactionId);
70
71 1
        return $event->getDeliveryStatus();
72
    }
73
74 5
    public function updateSentVerificationStatus($batchSize = 1)
75
    {
76 5
        $count = $this->sentVerificationRepo->countPendingUpdateSentVerification();
77
78 5
        if ($count === 0) {
79 1
            $this->comment('No messages pending update.');
80
81 1
            return [];
82
        }
83
84 4
        $query = $this->sentVerificationRepo->getPendingUpdateSentVerificationQuery();
85 4
        $sentVerifications = $query->iterate();
86
87 4
        $this->em->getConnection() ? $this->em->getConnection()->getConfiguration()->setSQLLogger(null) : null;
88 4
        gc_enable();
89 4
        $this->progressStart($count);
90 4
        $transactionsUpdated = [];
91 4
        foreach ($sentVerifications as $row) {
92
            /** @var SentVerificationInterface $sentVerification */
93 3
            $sentVerification = $row[0];
94 3
            $event = $this->getStatus($sentVerification->getTransactionId());
95 3
            if (false === $event->isUpdated()) {
96 2
                $this->progressAdvance(1);
97 2
                unset($event);
98 2
                unset($sentVerification);
99 2
                gc_collect_cycles();
100 2
                continue;
101
            }
102
103 1
            $deliveredAt = $event->getDeliveredAt();
104 1
            $sentVerification->setActuallySentAt($event->getSentAt())
105 1
                ->setDeliveredAt($deliveredAt)
106 1
                ->setFinished($deliveredAt instanceof \DateTime || $event->getDeliveryStatus()->isFinal());
107 1
            $transactionsUpdated[] = $sentVerification->getTransactionId();
108 1
            unset($event);
109 1
            unset($sentVerification);
110 1
            if ((count($transactionsUpdated) % $batchSize) === 0) {
111 1
                $this->em->flush();
112 1
                $this->em->clear();
113 1
                gc_collect_cycles();
114
            }
115 1
            $this->progressAdvance(1);
116
        }
117 4
        $this->em->flush();
118 4
        $this->em->clear();
119 4
        $this->progressFinish();
120
121 4
        $countUpdated = count($transactionsUpdated);
122 4
        $this->comment("Updated {$countUpdated} transactions.");
123
124 4
        if ($countUpdated === 0) {
125 3
            $this->comment("It's possible the SMS-sending service you are using doesn't implement status updates.");
126
        }
127
128 4
        return $transactionsUpdated;
129
    }
130
131
    /**
132
     * @param $amount
133
     * @return float average delivery time in seconds (abs value)
134
     */
135 3
    public function getAverageDeliveryTime($amount)
136
    {
137
        /** @var SentVerificationInterface[] $sentVerifications */
138 3
        $sentVerifications = $this->sentVerificationRepo->getLastDeliveredVerifications($amount);
139
140 3
        if (count($sentVerifications) === 0) {
141 2
            return 0;
142
        }
143
144 1
        $times = [];
145 1
        foreach ($sentVerifications as $sentVerification) {
146 1
            $times[] = abs(
147 1
                $sentVerification->getDeliveredAt()->format('U') - $sentVerification->getSentAt()->format('U')
148
            );
149
        }
150 1
        $sum = array_sum($times);
151
152 1
        $avg = $sum / count($times);
153
154 1
        return $avg;
155
    }
156
157
    /**
158
     * @param int $maxDeliverySeconds
159
     * @return array
160
     */
161 1
    public function getDelayedDeliveryTransactions($maxDeliverySeconds = 0)
162
    {
163 1
        $date = new \DateTime("-{$maxDeliverySeconds} seconds");
164 1
        $notDelivered = $this->sentVerificationRepo->getNotDeliveredSince($date);
165
166 1
        $transactions = [];
167 1
        foreach ($notDelivered as $sentVerification) {
168 1
            $transactions[] = [
169 1
                'transaction_id' => $sentVerification->getTransactionId(),
170 1
                'sent_at' => $sentVerification->getSentAt()->format('c'),
171
            ];
172
        }
173
174 1
        return $transactions;
175
    }
176
177
    /**
178
     * @param $transactionId
179
     * @return UpdateStatusEvent
180
     */
181 4
    private function getStatus($transactionId)
182
    {
183 4
        $event = new UpdateStatusEvent($transactionId);
184 4
        $this->dispatcher->dispatch(PhoneVerificationEvents::PHONE_VERIFICATION_GET_SENT_VERIFICATION_STATUS, $event);
185
186 4
        return $event;
187
    }
188
189 5
    private function comment($message)
190
    {
191 5
        if (!$this->io) {
192 1
            return;
193
        }
194 4
        $this->io->comment($message);
195 4
    }
196
197 4
    private function progressStart($max = 0)
198
    {
199 4
        if (!$this->io) {
200 1
            return;
201
        }
202 3
        $this->io->progressStart($max);
203 3
    }
204
205 3
    private function progressAdvance($step = 1)
206
    {
207 3
        if (!$this->io) {
208 1
            return;
209
        }
210 2
        $this->io->progressAdvance($step);
211 2
    }
212
213 4
    private function progressFinish()
214
    {
215 4
        if (!$this->io) {
216 1
            return;
217
        }
218 3
        $this->io->progressFinish();
219 3
    }
220
}
221