Passed
Pull Request — master (#3)
by Bartosz
04:27
created

AsyncReindexRunner::run()   A

Complexity

Conditions 2
Paths 5

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
c 0
b 0
f 0
rs 9.7666
cc 2
nc 5
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * File: AsyncReindexRunner.php
7
 *
8
 * @author Bartosz Kubicki [email protected]>
9
 * @author Paweł Papke <[email protected]>
10
 * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl)
11
 */
12
13
namespace LizardMedia\AdminIndexer\Model\ReindexRunner;
14
15
use LizardMedia\AdminIndexer\Api\Adapter\ReactPHP\ChildProcess\ProcessFactoryInterface;
16
use LizardMedia\AdminIndexer\Api\Adapter\ReactPHP\EventLoop\LoopFactoryInterface;
17
use LizardMedia\AdminIndexer\Api\ReindexRunner\AsyncReindexRunnerInterface;
18
use LizardMedia\AdminIndexer\Api\ReindexRunner\MessageBagInterface;
19
use LizardMedia\AdminIndexer\Exception\ReindexFailureAggregateException;
20
use Magento\Framework\Filesystem\DirectoryList;
21
use Magento\Framework\Indexer\IndexerRegistry;
22
use React\EventLoop\Factory as LoopFactory;
23
use React\EventLoop\LoopInterface;
24
use React\ChildProcess\Process;
25
26
/**
27
 * Class AsyncReindexRunner
28
 * @package LizardMedia\AdminIndexer\Model\ReindexRunner
29
 */
30
class AsyncReindexRunner implements AsyncReindexRunnerInterface
31
{
32
    /**
33
     * @var string
34
     */
35
    private const INDEXER_REINDEX_COMMAND = 'bin/magento indexer:reindex';
36
37
    /**
38
     * @var ProcessFactoryInterface
39
     */
40
    private $childProcessFactory;
41
42
    /**
43
     * @var LoopFactoryInterface
44
     */
45
    private $loopFactory;
46
47
    /**
48
     * @var MessageBagInterface
49
     */
50
    private $messageBag;
51
52
    /**
53
     * @var DirectoryList
54
     */
55
    private $directoryList;
56
57
    /**
58
     * @var IndexerRegistry
59
     */
60
    private $indexerRegistry;
61
62
    /**
63
     * AsyncReindexRunner constructor.
64
     * @param ProcessFactoryInterface $childProcessFactory
65
     * @param LoopFactoryInterface $loopFactory
66
     * @param MessageBagInterface $messageBag
67
     * @param DirectoryList $directoryList
68
     * @param IndexerRegistry $indexerRegistry
69
     */
70
    public function __construct(
71
        ProcessFactoryInterface $childProcessFactory,
72
        LoopFactoryInterface $loopFactory,
73
        MessageBagInterface $messageBag,
74
        DirectoryList $directoryList,
75
        IndexerRegistry $indexerRegistry
76
    ) {
77
        $this->childProcessFactory = $childProcessFactory;
78
        $this->loopFactory = $loopFactory;
79
        $this->messageBag = $messageBag;
80
        $this->directoryList = $directoryList;
81
        $this->indexerRegistry = $indexerRegistry;
82
    }
83
84
    /**
85
     * {@inheritDoc}
86
     */
87
    public function run(string ...$indexerIds): void
88
    {
89
        $this->informAboutIndexing($indexerIds);
90
        $indexerIds = $this->formatIndexersToBeReindex(...$indexerIds);
91
        $loop = $this->instantiateLoop();
92
93
        try {
94
            $command = $this->buildCommand($indexerIds);
95
            $process = $this->instantiateNewProcess($command);
96
            $process->start($loop);
97
            $loop->run();
98
        } catch (\Exception $exception) {
99
            $this->handleException($exception);
100
        }
101
    }
102
103
    /**
104
     * @param string[] ...$indexerIds
105
     * @return string
106
     */
107
    private function formatIndexersToBeReindex(string ...$indexerIds): string
108
    {
109
        return implode(' ', $indexerIds);
110
    }
111
112
    /**
113
     * @param array $indexerIds
114
     * @return void
115
     */
116
    private function informAboutIndexing(array $indexerIds): void
117
    {
118
        foreach ($indexerIds as $indexerId) {
119
            $this->messageBag->addMessage(__('Indexing of indexer %1 has been executed', $indexerId)->render());
120
        }
121
    }
122
123
    /**
124
     * @return LoopInterface
125
     */
126
    private function instantiateLoop(): LoopInterface
127
    {
128
        return $this->loopFactory->create();
129
    }
130
131
    /**
132
     * @param string $indexerIds
133
     * @return string
134
     */
135
    private function buildCommand(string $indexerIds): string
136
    {
137
        return sprintf(
138
            'php %s/%s %s > /dev/null 2>&1 &',
139
            $this->getRootDir(),
140
            self::INDEXER_REINDEX_COMMAND,
141
            $indexerIds
142
        );
143
    }
144
145
    /**
146
     * @return string
147
     */
148
    private function getRootDir(): string
149
    {
150
        return $this->directoryList->getRoot();
151
    }
152
153
    /**
154
     * @param string $command
155
     * @return Process
156
     */
157
    private function instantiateNewProcess(string $command): Process
158
    {
159
        return $this->childProcessFactory->create($command);
160
    }
161
162
163
    /**
164
     * @param \Exception $exception
165
     * @return void
166
     * @throws ReindexFailureAggregateException
167
     */
168
    private function handleException(\Exception $exception): void
169
    {
170
        throw new ReindexFailureAggregateException(
171
            __($exception->getMessage()),
172
            $exception,
173
            $exception->getCode()
174
        );
175
    }
176
}
177