Completed
Push — master ( 32513b...cc3a1a )
by Tim
06:16
created

PopulateCommand   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 0%

Importance

Changes 13
Bugs 6 Features 0
Metric Value
wmc 22
c 13
b 6
f 0
lcom 1
cbo 15
dl 0
loc 182
ccs 0
cts 101
cp 0
rs 9.1667

6 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 15 1
A initialize() 0 15 3
C execute() 0 40 11
A populateIndex() 0 19 3
A populateIndexType() 0 18 2
A refreshIndex() 0 9 2
1
<?php
2
3
namespace FOS\ElasticaBundle\Command;
4
5
use FOS\ElasticaBundle\Event\IndexPopulateEvent;
6
use FOS\ElasticaBundle\Event\TypePopulateEvent;
7
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
8
use Symfony\Component\Console\Helper\DialogHelper;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use FOS\ElasticaBundle\IndexManager;
13
use FOS\ElasticaBundle\Provider\ProviderRegistry;
14
use FOS\ElasticaBundle\Resetter;
15
use Symfony\Component\Console\Helper\ProgressBar;
16
17
/**
18
 * Populate the search index.
19
 */
20
class PopulateCommand extends ContainerAwareCommand
21
{
22
    /**
23
     * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
24
     */
25
    private $dispatcher;
26
27
    /**
28
     * @var IndexManager
29
     */
30
    private $indexManager;
31
32
    /**
33
     * @var ProgressClosureBuilder
34
     */
35
    private $progressClosureBuilder;
36
37
    /**
38
     * @var ProviderRegistry
39
     */
40
    private $providerRegistry;
41
42
    /**
43
     * @var Resetter
44
     */
45
    private $resetter;
46
47
    /**
48
     * @see Symfony\Component\Console\Command\Command::configure()
49
     */
50
    protected function configure()
51
    {
52
        $this
53
            ->setName('fos:elastica:populate')
54
            ->addOption('index', null, InputOption::VALUE_OPTIONAL, 'The index to repopulate')
55
            ->addOption('type', null, InputOption::VALUE_OPTIONAL, 'The type to repopulate')
56
            ->addOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset index before populating')
57
            ->addOption('offset', null, InputOption::VALUE_REQUIRED, 'Start indexing at offset', 0)
58
            ->addOption('sleep', null, InputOption::VALUE_REQUIRED, 'Sleep time between persisting iterations (microseconds)', 0)
59
            ->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Index packet size (overrides provider config option)')
60
            ->addOption('ignore-errors', null, InputOption::VALUE_NONE, 'Do not stop on errors')
61
            ->addOption('no-overwrite-format', null, InputOption::VALUE_NONE, 'Prevent this command from overwriting ProgressBar\'s formats')
62
            ->setDescription('Populates search indexes from providers')
63
        ;
64
    }
65
66
    /**
67
     * {@inheritDoc}
68
     */
69
    protected function initialize(InputInterface $input, OutputInterface $output)
70
    {
71
        $this->dispatcher = $this->getContainer()->get('event_dispatcher');
72
        $this->indexManager = $this->getContainer()->get('fos_elastica.index_manager');
73
        $this->providerRegistry = $this->getContainer()->get('fos_elastica.provider_registry');
74
        $this->resetter = $this->getContainer()->get('fos_elastica.resetter');
75
        $this->progressClosureBuilder = new ProgressClosureBuilder();
76
77
        if (!$input->getOption('no-overwrite-format') && class_exists('Symfony\\Component\\Console\\Helper\\ProgressBar')) {
78
            ProgressBar::setFormatDefinition('normal', " %current%/%max% [%bar%] %percent:3s%%\n%message%");
79
            ProgressBar::setFormatDefinition('verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%\n%message%");
80
            ProgressBar::setFormatDefinition('very_verbose', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n%message%");
81
            ProgressBar::setFormatDefinition('debug', " %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%\n%message%");
82
        }
83
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88
    protected function execute(InputInterface $input, OutputInterface $output)
89
    {
90
        $index = $input->getOption('index');
91
        $type = $input->getOption('type');
92
        $reset = !$input->getOption('no-reset');
93
        $options = array(
94
            'ignore_errors' => $input->getOption('ignore-errors'),
95
            'offset' => $input->getOption('offset'),
96
            'sleep' => $input->getOption('sleep')
97
        );
98
        if ($input->getOption('batch-size')) {
99
            $options['batch_size'] = (int) $input->getOption('batch-size');
100
        }
101
102
        if ($input->isInteractive() && $reset && $input->getOption('offset')) {
103
            /** @var DialogHelper $dialog */
104
            $dialog = $this->getHelperSet()->get('dialog');
105
            if (!$dialog->askConfirmation($output, '<question>You chose to reset the index and start indexing with an offset. Do you really want to do that?</question>', true)) {
106
                return;
107
            }
108
        }
109
110
        if (null === $index && null !== $type) {
111
            throw new \InvalidArgumentException('Cannot specify type option without an index.');
112
        }
113
114
        if (null !== $index) {
115
            if (null !== $type) {
116
                $this->populateIndexType($output, $index, $type, $reset, $options);
117
            } else {
118
                $this->populateIndex($output, $index, $reset, $options);
119
            }
120
        } else {
121
            $indexes = array_keys($this->indexManager->getAllIndexes());
122
123
            foreach ($indexes as $index) {
124
                $this->populateIndex($output, $index, $reset, $options);
125
            }
126
        }
127
    }
128
129
    /**
130
     * Recreates an index, populates its types, and refreshes the index.
131
     *
132
     * @param OutputInterface $output
133
     * @param string          $index
134
     * @param boolean         $reset
135
     * @param array           $options
136
     */
137
    private function populateIndex(OutputInterface $output, $index, $reset, $options)
138
    {
139
        $event = new IndexPopulateEvent($index, $reset, $options);
140
        $this->dispatcher->dispatch(IndexPopulateEvent::PRE_INDEX_POPULATE, $event);
141
142
        if ($event->isReset()) {
143
            $output->writeln(sprintf('<info>Resetting</info> <comment>%s</comment>', $index));
144
            $this->resetter->resetIndex($index, true);
145
        }
146
147
        $types = array_keys($this->providerRegistry->getIndexProviders($index));
148
        foreach ($types as $type) {
149
            $this->populateIndexType($output, $index, $type, false, $event->getOptions());
150
        }
151
152
        $this->dispatcher->dispatch(IndexPopulateEvent::POST_INDEX_POPULATE, $event);
153
154
        $this->refreshIndex($output, $index);
155
    }
156
157
    /**
158
     * Deletes/remaps an index type, populates it, and refreshes the index.
159
     *
160
     * @param OutputInterface $output
161
     * @param string          $index
162
     * @param string          $type
163
     * @param boolean         $reset
164
     * @param array           $options
165
     */
166
    private function populateIndexType(OutputInterface $output, $index, $type, $reset, $options)
167
    {
168
        $event = new TypePopulateEvent($index, $type, $reset, $options);
169
        $this->dispatcher->dispatch(TypePopulateEvent::PRE_TYPE_POPULATE, $event);
170
171
        if ($event->isReset()) {
172
            $output->writeln(sprintf('<info>Resetting</info> <comment>%s/%s</comment>', $index, $type));
173
            $this->resetter->resetIndexType($index, $type);
174
        }
175
176
        $provider = $this->providerRegistry->getProvider($index, $type);
177
        $loggerClosure = $this->progressClosureBuilder->build($output, 'Populating', $index, $type);
178
        $provider->populate($loggerClosure, $event->getOptions());
179
180
        $this->dispatcher->dispatch(TypePopulateEvent::POST_TYPE_POPULATE, $event);
181
182
        $this->refreshIndex($output, $index, false);
183
    }
184
185
    /**
186
     * Refreshes an index.
187
     *
188
     * @param OutputInterface $output
189
     * @param string          $index
190
     * @param bool            $postPopulate
191
     */
192
    private function refreshIndex(OutputInterface $output, $index, $postPopulate = true)
193
    {
194
        if ($postPopulate) {
195
            $this->resetter->postPopulate($index);
196
        }
197
198
        $output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
199
        $this->indexManager->getIndex($index)->refresh();
200
    }
201
}
202