Completed
Push — master ( ca8ded...dc27cf )
by Karel
22s queued 11s
created

PopulateCommand::populateIndexType()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 59

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 59
ccs 0
cts 39
cp 0
rs 8.5833
c 0
b 0
f 0
cc 5
nc 8
nop 5
crap 30

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
/*
4
 * This file is part of the FOSElasticaBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\ElasticaBundle\Command;
13
14
use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
15
use FOS\ElasticaBundle\Event\IndexPopulateEvent;
16
use FOS\ElasticaBundle\Event\TypePopulateEvent;
17
use FOS\ElasticaBundle\Index\IndexManager;
18
use FOS\ElasticaBundle\Index\Resetter;
19
use FOS\ElasticaBundle\Persister\Event\Events;
20
use FOS\ElasticaBundle\Persister\Event\OnExceptionEvent;
21
use FOS\ElasticaBundle\Persister\Event\PostAsyncInsertObjectsEvent;
22
use FOS\ElasticaBundle\Persister\Event\PostInsertObjectsEvent;
23
use FOS\ElasticaBundle\Persister\InPlacePagerPersister;
24
use FOS\ElasticaBundle\Persister\PagerPersisterInterface;
25
use FOS\ElasticaBundle\Persister\PagerPersisterRegistry;
26
use FOS\ElasticaBundle\Provider\PagerProviderRegistry;
27
use Symfony\Component\Console\Command\Command;
28
use Symfony\Component\Console\Helper\ProgressBar;
29
use Symfony\Component\Console\Helper\QuestionHelper;
30
use Symfony\Component\Console\Input\InputInterface;
31
use Symfony\Component\Console\Input\InputOption;
32
use Symfony\Component\Console\Output\OutputInterface;
33
use Symfony\Component\Console\Question\Question;
34
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
35
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
36
37
/**
38
 * Populate the search index.
39
 */
40
class PopulateCommand extends Command
41
{
42
    protected static $defaultName = 'fos:elastica:populate';
43
44
    /**
45
     * @var EventDispatcherInterface 
46
     */
47
    private $dispatcher;
48
49
    /**
50
     * @var IndexManager 
51
     */
52
    private $indexManager;
53
54
    /**
55
     * @var PagerProviderRegistry
56
     */
57
    private $pagerProviderRegistry;
58
59
    /**
60
     * @var PagerPersisterRegistry
61
     */
62
    private $pagerPersisterRegistry;
63
64
    /**
65
     * @var PagerPersisterInterface
66
     */
67
    private $pagerPersister;
68
69
    /**
70
     * @var Resetter
71
     */
72
    private $resetter;
73
74 4 View Code Duplication
    public function __construct(
75
        EventDispatcherInterface $dispatcher,
76
        IndexManager $indexManager,
77
        PagerProviderRegistry $pagerProviderRegistry,
78
        PagerPersisterRegistry $pagerPersisterRegistry,
79
        Resetter $resetter
80
    ) {
81 4
        parent::__construct();
82
83 4
        $this->dispatcher = $dispatcher;
84
85 4
        if (class_exists(LegacyEventDispatcherProxy::class)) {
86 4
            $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
87
        }
88
89 4
        $this->indexManager = $indexManager;
90 4
        $this->pagerProviderRegistry = $pagerProviderRegistry;
91 4
        $this->pagerPersisterRegistry = $pagerPersisterRegistry;
92 4
        $this->resetter = $resetter;
93 4
    }
94
95 4
    protected function configure()
96
    {
97
        $this
98 4
            ->setName('fos:elastica:populate')
99 4
            ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to repopulate')
100 4
            ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to repopulate')
101 4
            ->addOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset index before populating')
102 4
            ->addOption('no-delete', null, InputOption::VALUE_NONE, 'Do not delete index after populate')
103 4
            ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0)
104 4
            ->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Do not stop on errors')
105 4
            ->addOption('no-overwrite-format', null, InputOption::VALUE_NONE, 'Prevent this command from overwriting ProgressBar\'s formats')
106
107 4
            ->addOption('first-page', null, InputOption::VALUE_REQUIRED, 'The pager\'s page to start population from. Including the given page.', 1)
108 4
            ->addOption('last-page', null, InputOption::VALUE_REQUIRED, 'The pager\'s page to end population on. Including the given page.', null)
109 4
            ->addOption('max-per-page', null, InputOption::VALUE_REQUIRED, 'The pager\'s page size', 100)
110 4
            ->addOption('pager-persister', null, InputOption::VALUE_REQUIRED, 'The pager persister to be used to populate the index', InPlacePagerPersister::NAME)
111
112 4
            ->setDescription('Populates search indexes from providers')
113
        ;
114 4
    }
115
116
    protected function initialize(InputInterface $input, OutputInterface $output)
117
    {
118
        $this->pagerPersister = $this->pagerPersisterRegistry->getPagerPersister($input->getOption('pager-persister'));
119
120
        if (!$input->getOption('no-overwrite-format')) {
121
            ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%");
122
            ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%");
123
            ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%");
124
            ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%");
125
        }
126
    }
127
128
    protected function execute(InputInterface $input, OutputInterface $output)
129
    {
130
        $index = $input->getOption('index');
131
        $type = $input->getOption('type');
132
        $reset = !$input->getOption('no-reset');
133
        $delete = !$input->getOption('no-delete');
134
135
        $options = [
136
            'delete' => $delete,
137
            'reset' => $reset,
138
            'ignore_errors' => $input->getOption('ignore-errors'),
139
            'sleep' => $input->getOption('sleep'),
140
            'first_page' => $input->getOption('first-page'),
141
            'max_per_page' => $input->getOption('max-per-page'),
142
        ];
143
144
        if ($input->getOption('last-page')) {
145
            $options['last_page'] = $input->getOption('last-page');
146
        }
147
148
        if ($input->isInteractive() && $reset && 1 < $options['first_page']) {
149
            /** @var QuestionHelper $dialog */
150
            $dialog = $this->getHelperSet()->get('question');
151
            if (!$dialog->ask($input, $output, new Question('<question>You chose to reset the index and start indexing with an offset. Do you really want to do that?</question>'))) {
152
                return;
153
            }
154
        }
155
156
        if (null === $index && null !== $type) {
157
            throw new \InvalidArgumentException('Cannot specify type option without an index.');
158
        }
159
160
        if (null !== $index) {
161
            if (null !== $type) {
162
                $this->populateIndexType($output, $index, $type, $reset, $options);
163
            } else {
164
                $this->populateIndex($output, $index, $reset, $options);
165
            }
166
        } else {
167
            $indexes = array_keys($this->indexManager->getAllIndexes());
168
169
            foreach ($indexes as $index) {
170
                $this->populateIndex($output, $index, $reset, $options);
171
            }
172
        }
173
    }
174
175
    /**
176
     * Recreates an index, populates its types, and refreshes the index.
177
     *
178
     * @param OutputInterface $output
179
     * @param string          $index
180
     * @param bool            $reset
181
     * @param array           $options
182
     */
183
    private function populateIndex(OutputInterface $output, $index, $reset, $options)
184
    {
185
        $event = new IndexPopulateEvent($index, $reset, $options);
186
        $this->dispatcher->dispatch(IndexPopulateEvent::PRE_INDEX_POPULATE, $event);
187
188
        if ($event->isReset()) {
189
            $output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
190
            $this->resetter->resetIndex($index, true);
191
        }
192
193
        $types = array_keys($this->pagerProviderRegistry->getIndexProviders($index));
194
        foreach ($types as $type) {
195
            $this->populateIndexType($output, $index, $type, false, $event->getOptions());
196
        }
197
198
        $this->dispatcher->dispatch(IndexPopulateEvent::POST_INDEX_POPULATE, $event);
199
200
        $this->refreshIndex($output, $index);
201
    }
202
203
    /**
204
     * Deletes/remaps an index type, populates it, and refreshes the index.
205
     *
206
     * @param OutputInterface $output
207
     * @param string          $index
208
     * @param string          $type
209
     * @param bool            $reset
210
     * @param array           $options
211
     */
212
    private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options)
213
    {
214
        $event = new TypePopulateEvent($index, $type, $reset, $options);
215
        $this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event);
216
217
        if ($event->isReset()) {
218
            $output->writeln(sprintf('<info>Resetting</info> <comment>%s/%s</comment>', $index, $type));
219
            $this->resetter->resetIndexType($index, $type);
220
        }
221
222
        $offset = 1 < $options['first_page'] ? ($options['first_page'] - 1) * $options['max_per_page'] : 0;
223
        $loggerClosure = ProgressClosureBuilder::build($output, 'Populating', $index, $type, $offset);
224
225
        $this->dispatcher->addListener(
226
            Events::ON_EXCEPTION,
227
            function(OnExceptionEvent $event) use ($loggerClosure) {
228
                $loggerClosure(
229
                    count($event->getObjects()),
230
                    $event->getPager()->getNbResults(),
231
                    sprintf('<error>%s</error>', $event->getException()->getMessage())
232
                );
233
            }
234
        );
235
236
        $this->dispatcher->addListener(
237
            Events::POST_INSERT_OBJECTS,
238
            function(PostInsertObjectsEvent $event) use ($loggerClosure) {
239
                $loggerClosure(count($event->getObjects()), $event->getPager()->getNbResults());
240
            }
241
        );
242
243
        $this->dispatcher->addListener(
244
            Events::POST_ASYNC_INSERT_OBJECTS,
245
            function(PostAsyncInsertObjectsEvent $event) use ($loggerClosure) {
246
                $loggerClosure($event->getObjectsCount(), $event->getPager()->getNbResults(), $event->getErrorMessage());
247
            }
248
        );
249
250
        if ($options['ignore_errors']) {
251
            $this->dispatcher->addListener(Events::ON_EXCEPTION, function(OnExceptionEvent $event) {
252
                if ($event->getException() instanceof BulkResponseException) {
253
                    $event->setIgnore(true);
254
                }
255
            });
256
        }
257
258
        $provider = $this->pagerProviderRegistry->getProvider($index, $type);
259
260
        $pager = $provider->provide($options);
261
262
        $options['indexName'] = $index;
263
        $options['typeName'] = $type;
264
265
        $this->pagerPersister->insert($pager, $options);
266
267
        $this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event);
268
269
        $this->refreshIndex($output, $index);
270
    }
271
272
    /**
273
     * Refreshes an index.
274
     *
275
     * @param OutputInterface $output
276
     * @param string          $index
277
     */
278
    private function refreshIndex(OutputInterface $output, $index)
279
    {
280
        $output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
281
        $this->indexManager->getIndex($index)->refresh();
282
        $output->writeln("");
283
    }
284
}
285