Completed
Push — issue#702 ( 5ffcbe...91bd46 )
by Guilherme
03:29
created

SmsStatusService::setSymfonyStyle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
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\DeliveryStatus;
17
use LoginCidadao\PhoneVerificationBundle\Model\SentVerificationInterface;
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
    public function updateSentVerificationStatus($batchSize = 1)
64
    {
65
        $count = $this->sentVerificationRepo->countPendingUpdateSentVerification();
66
67
        if ($count === 0) {
68
            $this->comment('No messages pending update.');
69
70
            return [];
71
        }
72
73
        $query = $this->sentVerificationRepo->getPendingUpdateSentVerificationQuery();
74
        $sentVerifications = $query->iterate();
75
76
        $this->progressStart($count);
77
        $transactionsUpdated = [];
78
        foreach ($sentVerifications as $row) {
79
            /** @var SentVerificationInterface $sentVerification */
80
            $sentVerification = $row[0];
81
            $status = $this->getStatus($sentVerification->getTransactionId());
82
83
            if (false === $status->isUpdated()) {
84
                $this->progressAdvance(1);
85
                continue;
86
            }
87
88
            $deliveredAt = $status->getDeliveredAt();
89
            $sentVerification->setActuallySentAt($status->getSentAt())
90
                ->setDeliveredAt($deliveredAt)
91
                ->setFinished(
92
                    $deliveredAt instanceof \DateTime || DeliveryStatus::isFinal($status->getDeliveryStatus())
93
                );
94
            $transactionsUpdated[] = $sentVerification->getTransactionId();
95
            if ((count($transactionsUpdated) % $batchSize) === 0) {
96
                $this->em->flush();
97
                $this->em->clear();
98
            }
99
            $this->progressAdvance(1);
100
        }
101
        $this->em->flush();
102
        $this->em->clear();
103
        $this->progressFinish();
104
105
        $countUpdated = count($transactionsUpdated);
106
        $this->comment("Updated {$countUpdated} transactions.");
107
108
        if ($countUpdated === 0) {
109
            $this->comment("It's possible the SMS-sending service you are using doesn't implement status updates.");
110
        }
111
112
        return $transactionsUpdated;
113
    }
114
115
    /**
116
     * @param $amount
117
     * @return float average delivery time in seconds (abs value)
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
118
     */
119
    public function getAverageDeliveryTime($amount)
120
    {
121
        /** @var SentVerificationInterface[] $sentVerifications */
122
        $sentVerifications = $this->sentVerificationRepo->getLastDeliveredVerifications($amount);
123
124
        if (count($sentVerifications) === 0) {
125
            return 0;
126
        }
127
128
        $times = [];
129
        foreach ($sentVerifications as $sentVerification) {
130
            $times[] = abs(
131
                $sentVerification->getDeliveredAt()->format('U') - $sentVerification->getSentAt()->format('U')
132
            );
133
        }
134
        $sum = array_sum($times);
135
136
        $avg = $sum / count($times);
137
138
        return $avg;
139
    }
140
141
    /**
142
     * @param int $maxDeliverySeconds
143
     * @return array
144
     */
145
    public function getDelayedDeliveryTransactions($maxDeliverySeconds = 0)
146
    {
147
        $date = new \DateTime("-{$maxDeliverySeconds} seconds");
148
        $notDelivered = $this->sentVerificationRepo->getNotDeliveredSince($date);
149
150
        $transactions = [];
151
        foreach ($notDelivered as $sentVerification) {
152
            $transactions[] = [
153
                'transaction_id' => $sentVerification->getTransactionId(),
154
                'sent_at' => $sentVerification->getSentAt()->format('c'),
155
            ];
156
        }
157
158
        return $transactions;
159
    }
160
161
    /**
162
     * @param $transactionId
163
     * @return UpdateStatusEvent
164
     */
165
    private function getStatus($transactionId)
166
    {
167
        $event = new UpdateStatusEvent($transactionId);
168
        $this->dispatcher->dispatch(PhoneVerificationEvents::PHONE_VERIFICATION_GET_SENT_VERIFICATION_STATUS, $event);
169
170
        return $event;
171
    }
172
173
    private function comment($message)
174
    {
175
        if (!$this->io) {
176
            return;
177
        }
178
        $this->io->comment($message);
179
    }
180
181
    private function progressStart($max = 0)
182
    {
183
        if (!$this->io) {
184
            return;
185
        }
186
        $this->io->progressStart($max);
187
    }
188
189
    private function progressAdvance($step = 1)
190
    {
191
        if (!$this->io) {
192
            return;
193
        }
194
        $this->io->progressAdvance($step);
195
    }
196
197
    private function progressFinish()
198
    {
199
        if (!$this->io) {
200
            return;
201
        }
202
        $this->io->progressFinish();
203
    }
204
}
205