ReindexCommand::reindex()   B
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 33
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 23
nc 3
nop 2
1
<?php
2
/*
3
 * WellCommerce Open-Source E-Commerce Platform
4
 * 
5
 * This file is part of the WellCommerce package.
6
 *
7
 * (c) Adam Piotrowski <[email protected]>
8
 * 
9
 * For the full copyright and license information,
10
 * please view the LICENSE file that was distributed with this source code.
11
 */
12
13
namespace WellCommerce\Bundle\SearchBundle\Command;
14
15
use Doctrine\Common\Collections\ArrayCollection;
16
use Doctrine\Common\Collections\Collection;
17
use Doctrine\Common\Collections\Criteria;
18
use Doctrine\ORM\Tools\Pagination\Paginator;
19
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
20
use Symfony\Component\Console\Helper\ProgressBar;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use WellCommerce\Bundle\AppBundle\Entity\Locale;
25
use WellCommerce\Bundle\CoreBundle\Doctrine\Repository\RepositoryInterface;
26
use WellCommerce\Bundle\SearchBundle\Manager\SearchManagerInterface;
27
use WellCommerce\Component\Search\Model\TypeInterface;
28
29
/**
30
 * Class ReindexCommand
31
 *
32
 * @author  Adam Piotrowski <[email protected]>
33
 */
34
final class ReindexCommand extends ContainerAwareCommand
35
{
36
    /**
37
     * @var TypeInterface
38
     */
39
    private $type;
40
    
41
    /**
42
     * @var int
43
     */
44
    private $batchSize;
45
    
46
    /**
47
     * @var RepositoryInterface
48
     */
49
    private $repository;
50
    
51
    /**
52
     * @var SearchManagerInterface
53
     */
54
    private $manager;
55
    
56
    protected function configure()
57
    {
58
        $this->setDescription('Reindexes search types');
59
        $this->setName('wellcommerce:search:reindex');
60
        
61
        $this->addOption(
62
            'type',
63
            null,
64
            InputOption::VALUE_REQUIRED,
65
            'Index type',
66
            'product'
67
        );
68
        
69
        $this->addOption(
70
            'batch',
71
            null,
72
            InputOption::VALUE_REQUIRED,
73
            'Batch size',
74
            150
75
        );
76
        
77
        $this->addOption(
78
            'repository',
79
            null,
80
            InputOption::VALUE_REQUIRED,
81
            'Repository service',
82
            'product.repository'
83
        );
84
    }
85
    
86
    protected function initialize(InputInterface $input, OutputInterface $output)
87
    {
88
        $this->manager    = $this->getSearchManager();
89
        $this->type       = $this->manager->getType($input->getOption('type'));
90
        $this->batchSize  = $input->getOption('batch');
91
        $this->repository = $this->getRepository($input->getOption('repository'));
92
    }
93
    
94
    protected function execute(InputInterface $input, OutputInterface $output)
95
    {
96
        $this->getContainer()->get('doctrine.helper')->disableFilter('locale');
97
        
98
        $this->getLocales()->map(function (Locale $locale) use ($output) {
99
            $output->writeln(sprintf('<info>Reindexing locale:</info> %s', $locale->getCode()));
100
            $this->reindex($locale->getCode(), $output);
101
        });
102
    }
103
    
104
    private function reindex(string $locale, OutputInterface $output)
105
    {
106
        $totalEntities = $this->getTotalCount();
107
        $iterations    = $this->getIterations($totalEntities, $this->batchSize);
108
        
109
        $output->writeln(sprintf('<comment>Total entities:</comment> %s', $totalEntities));
110
        $output->writeln(sprintf('<comment>Batch size:</comment> %s', $this->batchSize));
111
        $output->writeln(sprintf('<comment>Iterations:</comment> %s', count($iterations)));
112
        $output->writeln(sprintf('<comment>Locale:</comment> %s', $locale));
113
        
114
        $output->writeln('<info>Flushing index</info>');
115
        $this->manager->removeIndex($locale, $this->type->getName());
116
        $this->manager->createIndex($locale, $this->type->getName());
117
        
118
        $progress = new ProgressBar($output, count($iterations));
119
        $progress->setFormat('verbose');
120
        $progress->setRedrawFrequency($this->batchSize);
121
        $progress->start();
122
        
123
        foreach ($iterations as $iteration) {
124
            $entities  = $this->getEntities($iteration);
125
            $documents = new ArrayCollection();
126
            foreach ($entities as $entity) {
127
                $document = $this->type->createDocument($entity, $locale);
128
                $documents->add($document);
129
            }
130
            
131
            $this->manager->addDocuments($documents, $locale, $this->type->getName());
132
            $progress->advance();
133
        }
134
        
135
        $progress->finish();
136
    }
137
    
138
    private function getEntities(int $iteration): array
139
    {
140
        return $this->repository->findBy([], null, $this->batchSize, $iteration * $this->batchSize);
141
    }
142
    
143
    private function getLocales(): Collection
144
    {
145
        $criteria = new Criteria();
146
        $criteria->andWhere($criteria->expr()->eq('enabled', true));
147
        
148
        return $this->getContainer()->get('locale.repository')->matching($criteria);
149
    }
150
    
151
    private function getRepository(string $serviceId): RepositoryInterface
152
    {
153
        if (false === $this->getContainer()->has($serviceId)) {
154
            return $this->getContainer()->get($this->type->getName() . '.repository');
155
        }
156
        
157
        return $this->getContainer()->get($serviceId);
158
    }
159
    
160
    private function getIterations(int $total, int $batchSize): array
161
    {
162
        return range(0, ceil($total / $batchSize));
163
    }
164
    
165
    private function getSearchManager(): SearchManagerInterface
166
    {
167
        return $this->getContainer()->get('search.manager');
168
    }
169
    
170
    private function getTotalCount(): int
171
    {
172
        $queryBuilder = $this->repository->getQueryBuilder();
173
        $query        = $queryBuilder->getQuery();
174
        $query->useQueryCache(true);
175
        $query->useResultCache(true);
176
        $paginator = new Paginator($query, true);
177
        $paginator->setUseOutputWalkers(false);
178
        
179
        return $paginator->count();
180
    }
181
}
182