Test Setup Failed
Push — master ( d6bd2d...bc363c )
by Alexey
03:03
created

UpdateSubscriptionsCommand::setUserRepository()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Skobkin\Bundle\PointToolsBundle\Command;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Psr\Log\LoggerInterface;
7
use Skobkin\Bundle\PointToolsBundle\Entity\Subscription;
8
use Skobkin\Bundle\PointToolsBundle\Entity\User;
9
use Skobkin\Bundle\PointToolsBundle\Repository\UserRepository;
10
use Skobkin\Bundle\PointToolsBundle\Service\SubscriptionsManager;
11
use Skobkin\Bundle\PointToolsBundle\Service\UserApi;
12
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
13
use Symfony\Component\Console\Helper\ProgressBar;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
18
/**
19
 * @todo https://symfony.com/doc/current/console/lockable_trait.html
20
 */
21
class UpdateSubscriptionsCommand extends ContainerAwareCommand
22
{
23
    /**
24
     * @var EntityManagerInterface
25
     */
26
    private $em;
27
28
    /**
29
     * @var LoggerInterface
30
     */
31
    private $logger;
32
33
    /**
34
     * @var UserRepository
35
     */
36
    private $userRepo;
37
38
    /**
39
     * @var InputInterface
40
     */
41
    private $input;
42
43
    /**
44
     * @var UserApi
45
     */
46
    private $api;
47
48
    /**
49
     * @var int
50
     */
51
    private $apiDelay = 500000;
52
53
    /**
54
     * @var SubscriptionsManager
55
     */
56
    private $subscriptionManager;
57
58
    /**
59
     * @var ProgressBar
60
     */
61
    private $progress;
62
63
64
    public function setLogger(LoggerInterface $logger)
65
    {
66
        $this->logger = $logger;
67
    }
68
69
    public function setEntityManager(EntityManagerInterface $em)
70
    {
71
        $this->em = $em;
72
    }
73
74
    public function setUserRepository(UserRepository $repository)
75
    {
76
        $this->userRepo = $repository;
77
    }
78
79
    public function setApiClient(UserApi $userApi)
80
    {
81
        $this->api = $userApi;
82
    }
83
84
    public function setApiDelay(int $microSecs)
85
    {
86
        $this->apiDelay = $microSecs;
87
    }
88
89
    public function setSubscriptionManager(SubscriptionsManager $subscriptionsManager)
90
    {
91
        $this->subscriptionManager = $subscriptionsManager;
92
    }
93
94
    protected function configure()
95
    {
96
        $this
97
            ->setName('point:update:subscriptions')
98
            ->setDescription('Update subscriptions of users subscribed to service')
99
            ->addOption(
100
                'all-users',
101
                null,
102
                InputOption::VALUE_NONE,
103
                'If set, command will check subscribers of all service users instead of service subscribers only'
104
            )
105
            ->addOption(
106
                'check-only',
107
                null,
108
                InputOption::VALUE_NONE,
109
                'If set, command will not perform write operations in the database'
110
            )
111
            // @todo add option for checking only selected user
112
        ;
113
    }
114
115
    /**
116
     * @param InputInterface $input
117
     * @param OutputInterface $output
118
     *
119
     * @return int
120
     */
121
    protected function execute(InputInterface $input, OutputInterface $output)
122
    {
123
        $this->input = $input;
124
125
        $this->logger->debug('UpdateSubscriptionsCommand started.');
126
127
        try {
128
            $appUserId = $this->getContainer()->getParameter('point_id');
129
        } catch (\InvalidArgumentException $e) {
130
            $this->logger->alert('Could not get point_id parameter from config file', ['exception_message' => $e->getMessage()]);
131
            return 1;
132
        }
133
134
        $this->progress = new ProgressBar($output);
135
        $this->progress->setFormat('debug');
136
137
        // Beginning transaction for all changes
138
        $this->em->beginTransaction();
139
140
        $this->progress->setMessage('Getting service subscribers');
141
142
        try {
143
            $usersForUpdate = $this->getUsersForUpdate($appUserId);
144
        } catch (\Exception $e) {
145
            $this->logger->error('Error while getting service subscribers', ['exception' => get_class($e), 'message' => $e->getMessage()]);
146
147
            return 1;
148
        }
149
150
        if (0 === count($usersForUpdate)) {
151
            $this->logger->info('No local subscribers. Finishing.');
152
153
            return 0;
154
        }
155
156
        $this->logger->info('Processing users subscribers');
157
        $this->progress->setMessage('Processing users subscribers');
158
        $this->progress->start(count($usersForUpdate));
159
160
        $this->updateUsersSubscribers($usersForUpdate);
161
162
        $this->progress->finish();
163
164
        // Flushing all changes at once to database
165
        $this->em->flush();
166
        $this->em->commit();
167
168
        $this->logger->debug('Finished');
169
170
        return 0;
171
    }
172
173
    /**
174
     * @param User[] $users
175
     */
176
    private function updateUsersSubscribers(array $users)
177
    {
178
        // Updating users subscribers
179
        foreach ($users as $user) {
180
            $this->logger->info('Processing @'.$user->getLogin());
181
182
            try {
183
                $userCurrentSubscribers = $this->api->getUserSubscribersById($user->getId());
184
            } catch (\Exception $e) {
185
                $this->logger->error(
186
                    'Error while getting subscribers. Skipping.',
187
                    [
188
                        'user_login' => $user->getLogin(),
189
                        'user_id' => $user->getId(),
190
                        'message' => $e->getMessage(),
191
                        'file' => $e->getFile(),
192
                        'line' => $e->getLine(),
193
                    ]
194
                );
195
196
                continue;
197
            }
198
199
            $this->logger->debug('Updating user subscribers');
200
201
            try {
202
                // Updating user subscribers
203
                $this->subscriptionManager->updateUserSubscribers($user, $userCurrentSubscribers);
204
            } catch (\Exception $e) {
205
                $this->logger->error(
206
                    'Error while updating user subscribers',
207
                    [
208
                        'user_login' => $user->getLogin(),
209
                        'user_id' => $user->getId(),
210
                        'message' => $e->getMessage(),
211
                        'file' => $e->getFile(),
212
                        'line' => $e->getLine(),
213
                    ]
214
                );
215
            }
216
217
            $this->progress->advance();
218
219
            usleep($this->apiDelay);
220
        }
221
    }
222
223
    private function getUsersForUpdate(int $appUserId): array
224
    {
225
        if ($this->input->getOption('all-users')) {
226
            $usersForUpdate = $this->userRepo->findAll();
227
        } else {
228
            /** @var User $serviceUser */
229
            $serviceUser = $this->userRepo->find($appUserId);
230
231
            if (!$serviceUser) {
232
                $this->logger->info('Service user not found');
233
                // @todo Retrieving user
234
235
                throw new \RuntimeException('Service user not found in the database');
236
            }
237
238
            $this->logger->info('Getting service subscribers');
239
240
            try {
241
                $usersForUpdate = $this->api->getUserSubscribersById($appUserId);
242
            } catch (\Exception $e) {
243
                $this->logger->warning(
244
                    'Error while getting service subscribers. Fallback to local list.',
245
                    [
246
                        'user_login' => $serviceUser->getLogin(),
247
                        'user_id' => $serviceUser->getId(),
248
                        'message' => $e->getMessage(),
249
                        'file' => $e->getFile(),
250
                        'line' => $e->getLine(),
251
                    ]
252
                );
253
254
                $usersForUpdate = [];
255
256
                /** @var Subscription $subscription */
257
                foreach ((array) $serviceUser->getSubscribers() as $subscription) {
258
                    $usersForUpdate[] = $subscription->getSubscriber();
259
                }
260
            }
261
262
            $this->logger->debug('Updating service subscribers');
263
264
            // Updating service subscribers
265
            try {
266
                $this->subscriptionManager->updateUserSubscribers($serviceUser, $usersForUpdate);
267
            } catch (\Exception $e) {
268
                $this->logger->error(
269
                    'Error while updating service subscribers',
270
                    [
271
                        'user_login' => $serviceUser->getLogin(),
272
                        'user_id' => $serviceUser->getId(),
273
                        'message' => $e->getMessage(),
274
                        'file' => $e->getFile(),
275
                        'line' => $e->getLine(),
276
                    ]
277
                );
278
279
                throw $e;
280
            }
281
        }
282
283
        return $usersForUpdate;
284
    }
285
}