StartWebapiReportingService::startProcesses()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
dl 9
loc 9
c 0
b 0
f 0
rs 9.9666
cc 2
nc 2
nop 2
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * File: StartWebapiReportingService.php
6
 *
7
 * @author      Maciej Sławik <[email protected]>
8
 * Github:      https://github.com/maciejslawik
9
 */
10
11
namespace MSlwk\ReactPhpPlayground\Console\Command;
12
13
use Magento\Framework\Serialize\Serializer\Json;
14
use Magento\Store\Model\StoreManagerInterface;
15
use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface;
16
use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface;
17
use MSlwk\ReactPhpPlayground\Api\TimerInterface;
18
use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory;
19
use React\EventLoop\Factory;
20
use React\EventLoop\LoopInterface;
21
use Symfony\Component\Console\Command\Command;
22
use Symfony\Component\Console\Input\InputArgument;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use React\HttpClient\Response;
26
27
/**
28
 * Class StartWebapiReportingService
29
 * @package MSlwk\ReactPhpPlayground\Console\Command
30
 */
31
class StartWebapiReportingService extends Command
32
{
33
    const COMMAND_NAME = 'mslwk:webapi-reporting-start';
34
    const COMMAND_DESCRIPTION = 'Start asynchronous WebAPI reporting service';
35
    const ARGUMENT_NUMBER_OF_THREADS = 'threads';
36
37
    const API_ENDPOINT_PATH = 'rest/V1/mslwk/customer-report/generate';
38
39
    /**
40
     * @var TimerInterface
41
     */
42
    private $timer;
43
44
    /**
45
     * @var CustomerIdsProviderInterface
46
     */
47
    private $customerIdsProvider;
48
49
    /**
50
     * @var LoopInterface
51
     */
52
    private $loop;
53
54
    /**
55
     * @var ClientFactory
56
     */
57
    private $clientFactory;
58
59
    /**
60
     * @var Json
61
     */
62
    private $jsonHandler;
63
64
    /**
65
     * @var StoreManagerInterface
66
     */
67
    private $storeManager;
68
69
    /**
70
     * @var ChunkSizeCalculatorInterface
71
     */
72
    private $chunkSizeCalculator;
73
74
    /**
75
     * StartWebapiReportingService constructor.
76
     * @param TimerInterface $timer
77
     * @param CustomerIdsProviderInterface $customerIdsProvider
78
     * @param Factory $loopFactory
79
     * @param ClientFactory $clientFactory
80
     * @param Json $jsonHandler
81
     * @param StoreManagerInterface $storeManager
82
     * @param ChunkSizeCalculatorInterface $chunkSizeCalculator
83
     * @param null $name
84
     */
85 View Code Duplication
    public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
        TimerInterface $timer,
87
        CustomerIdsProviderInterface $customerIdsProvider,
88
        Factory $loopFactory,
89
        ClientFactory $clientFactory,
90
        Json $jsonHandler,
91
        StoreManagerInterface $storeManager,
92
        ChunkSizeCalculatorInterface $chunkSizeCalculator,
93
        $name = null
94
    ) {
95
        parent::__construct($name);
96
        $this->timer = $timer;
97
        $this->customerIdsProvider = $customerIdsProvider;
98
        $this->loop = $loopFactory::create();
99
        $this->clientFactory = $clientFactory;
100
        $this->jsonHandler = $jsonHandler;
101
        $this->storeManager = $storeManager;
102
        $this->chunkSizeCalculator = $chunkSizeCalculator;
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    protected function configure()
109
    {
110
        $this->setName(self::COMMAND_NAME)
111
            ->setDescription(self::COMMAND_DESCRIPTION)
112
            ->addArgument(
113
                self::ARGUMENT_NUMBER_OF_THREADS,
114
                InputArgument::REQUIRED,
115
                'Number of threads for running the export process'
116
            );
117
    }
118
119
    /**
120
     * @param InputInterface $input
121
     * @param OutputInterface $output
122
     * @return void
123
     */
124 View Code Duplication
    protected function execute(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
125
    {
126
        $customerIds = $this->customerIdsProvider->getCustomerIds();
127
        $numberOfThreads = (int)$input->getArgument(self::ARGUMENT_NUMBER_OF_THREADS);
128
129
        $this->timer->startTimer();
130
131
        $this->startProcesses($customerIds, $numberOfThreads);
132
133
        $this->timer->stopTimer();
134
135
        $output->writeln("<info>Process finished after {$this->timer->getExecutionTimeInSeconds()} seconds</info>");
136
    }
137
138
    /**
139
     * @param array $customerIds
140
     * @param int $numberOfThreads
141
     */
142 View Code Duplication
    protected function startProcesses(array $customerIds, int $numberOfThreads): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
    {
144
        $chunkSize = $this->chunkSizeCalculator->calculateChunkSize($customerIds, $numberOfThreads);
145
        $threadedCustomerIds = array_chunk($customerIds, $chunkSize);
146
        foreach ($threadedCustomerIds as $customerIdsForSingleThread) {
147
            $this->createRequestDefinition($customerIdsForSingleThread);
148
        }
149
        $this->loop->run();
150
    }
151
152
    /**
153
     * @param int[] $customerIds
154
     */
155
    protected function createRequestDefinition(array $customerIds): void
156
    {
157
        $client = $this->clientFactory->create($this->loop);
158
        $data = $this->jsonHandler->serialize(['customerIds' => $customerIds]);
159
        $request = $client->request(
160
            'POST',
161
            $this->getRequestUrl(),
162
            [
163
                'Content-Type' => 'application/json',
164
                'Content-Length' => strlen($data)
165
            ]
166
        );
167
        $request->write($data);
168
        $request->on('response', function (Response $response) use (&$htmlObjectArray) {
169
            $data = '';
170
            $response->on(
171
                'data',
172
                function ($chunk) use (&$data) {
173
                    $data .= $chunk;
174
                }
175
            )->on(
176
                'end',
177
                function () use (&$data) {
178
                    foreach ($this->jsonHandler->unserialize($data) as $message) {
179
                        echo $message;
180
                    }
181
                }
182
            );
183
        });
184
        $request->end();
185
    }
186
187
    /**
188
     * @return string
189
     */
190
    protected function getRequestUrl(): string
191
    {
192
        return $this->storeManager->getStore()->getBaseUrl() . self::API_ENDPOINT_PATH;
193
    }
194
}
195