Completed
Push — master ( bd1580...0ea8fb )
by Florian
09:56
created

SyncCommand::getEntityToDocumentMapper()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
declare(strict_types=1);
3
4
/*
5
 * This file is part of the Stinger Entity Search package.
6
 *
7
 * (c) Oliver Kotte <[email protected]>
8
 * (c) Florian Meyer <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace StingerSoft\EntitySearchBundle\Command;
15
16
use Doctrine\Common\Persistence\ObjectManager;
17
use Doctrine\DBAL\Platforms\SQLServerPlatform;
18
use Doctrine\ORM\EntityManager;
19
use Doctrine\ORM\Mapping\ClassMetadata;
20
use StingerSoft\EntitySearchBundle\Services\Mapping\EntityToDocumentMapperInterface;
21
use StingerSoft\EntitySearchBundle\Services\SearchService;
22
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
23
use Symfony\Component\Console\Command\Command;
24
use Symfony\Component\Console\Helper\ProgressBar;
25
use Symfony\Component\Console\Input\InputArgument;
26
use Symfony\Component\Console\Input\InputInterface;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\HttpKernel\Kernel;
29
use Symfony\Component\HttpKernel\KernelInterface;
30
31
class SyncCommand extends Command {
32
33
	/**
34
	 * @var string|null The default command name
35
	 */
36
	protected static $defaultName = 'stinger:search:sync';
37
38
	/**
39
	 *
40
	 * @var EntityToDocumentMapperInterface
41
	 */
42
	protected $entityToDocumentMapper;
43
44
	/**
45
	 *
46
	 * @var SearchService
47
	 */
48
	protected $searchService;
49
50
	/**
51
	 *
52
	 * Cache for the default upload path of this platform
53
	 *
54
	 * @var string
55
	 */
56
	protected static $defaultUploadPath = null;
57
58
	public function __construct(SearchService $searchService, EntityToDocumentMapperInterface $mapper, KernelInterface $kernel) {
59
		parent::__construct();
60
		$this->searchService = $searchService;
61
		$this->entityToDocumentMapper = $mapper;
62
		// Detect upload path
63
		if(!self::$defaultUploadPath) {
64
			if(Kernel::VERSION_ID < 40200) {
65
				$root = $kernel->getRootDir();
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\HttpKe...Interface::getRootDir() has been deprecated with message: since Symfony 4.2

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
66
			} else {
67
				$root = $kernel->getProjectDir();
68
			}
69
			self::$defaultUploadPath = $root . '/../web/uploads';
70
		}
71
	}
72
73
	/**
74
	 *
75
	 * {@inheritdoc}
76
	 *
77
	 * @see \Symfony\Component\Console\Command\Command::configure()
78
	 */
79
	protected function configure() {
80
		/* @formatter:off */
81
		$this
82
			->addArgument('entity', InputArgument::REQUIRED, 'The entity you want to index')
83
			->addOption('source', null, InputArgument::OPTIONAL, 'specify a source from where to load entities [relational, mongodb] (unsupported!)', 'relational')
84
			->setDescription('Index all entities');
85
		/* @formatter:on */
86
	}
87
88
	/**
89
	 *
90
	 * {@inheritdoc}
91
	 *
92
	 * @see \Symfony\Component\Console\Command\Command::execute()
93
	 * @throws \Doctrine\Common\Persistence\Mapping\MappingException
94
	 * @throws \Doctrine\DBAL\DBALException
95
	 * @throws \Doctrine\ORM\NonUniqueResultException
96
	 * @throws \Doctrine\ORM\ORMException
97
	 * @throws \Doctrine\ORM\OptimisticLockException
98
	 */
99
	protected function execute(InputInterface $input, OutputInterface $output) {
100
101
102
		// Get the entity argument
103
		$entity = $input->getArgument('entity');
104
105
		if($entity === 'all') {
106
			/**
107
			 * @var EntityManager $entityManager
108
			 */
109
			$entityManager = $this->searchService->getObjectManager();
110
111
			$meta = $entityManager->getMetadataFactory()->getAllMetadata();
112
113
			/**
114
			 * @var ClassMetadata $m
115
			 */
116
			foreach($meta as $m) {
117
118
				if($m->getReflectionClass()->isAbstract() || $m->getReflectionClass()->isInterface()) {
119
					continue;
120
				}
121
				if(!$this->entityToDocumentMapper->isClassIndexable($m->getReflectionClass()->getName())) {
122
					continue;
123
				}
124
				$this->indexEntity($input, $output, $m->getReflectionClass()->getName());
125
				$output->writeln('');
126
			}
127
		} else {
128
			$this->indexEntity($input, $output, $entity);
129
		}
130
	}
131
132
	/**
133
	 * @param InputInterface $input
134
	 * @param OutputInterface $output
135
	 * @param $entity
136
	 * @throws \Doctrine\Common\Persistence\Mapping\MappingException
137
	 * @throws \Doctrine\DBAL\DBALException
138
	 * @throws \Doctrine\ORM\NonUniqueResultException
139
	 * @throws \Doctrine\ORM\ORMException
140
	 * @throws \Doctrine\ORM\OptimisticLockException
141
	 */
142
	protected function indexEntity(InputInterface $input, OutputInterface $output, $entity) {
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
143
		$output->writeln(sprintf('<comment>Indexing entities of type "%s"</comment>', $entity));
144
		/**
145
		 *
146
		 * @var EntityManager $entityManager
147
		 */
148
		$entityManager = $this->searchService->getObjectManager();
149
		$repository = null;
150
		try {
151
			// Get repository for the given entity type
152
			$repository = $entityManager->getRepository($entity);
153
		} catch(\Exception $e) {
154
			$output->writeln(sprintf('<error>No repository found for "%s", check your input</error>', $entity));
155
			return;
156
		}
157
158
		// Get all entities
159
		$queryBuilder = $repository->createQueryBuilder('e');
160
		$countQueryBuilder = $repository->createQueryBuilder('e')->select('COUNT(e)');
161
		$entityCount = (int)$countQueryBuilder->getQuery()->getSingleScalarResult();
162
163
		$useBatch = !($entityManager->getConnection()->getDatabasePlatform() instanceof SQLServerPlatform);
164
		$iterableResult = $useBatch ? $queryBuilder->getQuery()->iterate() : $queryBuilder->getQuery()->getResult();
165
		if($entityCount === 0) {
166
			$output->writeln('<comment>No entities found for indexing</comment>');
167
			return;
168
		}
169
		$progressBar = new ProgressBar($output, $entityCount);
170
		$progressBar->display();
171
172
		$entitiesIndexed = 0;
173
174
		// Index each entity separate
175
		foreach($iterableResult as $row) {
176
			$entity = $useBatch ? $row[0] : $row;
177
			$progressBar->advance();
178
			if($this->entityToDocumentMapper->isIndexable($entity)) {
179
				$document = $this->entityToDocumentMapper->createDocument($entityManager, $entity);
180
				if($document === null) {
181
					continue;
182
				}
183
				try {
184
					$this->searchService->saveDocument($document);
185
					$entitiesIndexed++;
186
				} catch(\Exception $e) {
187
					$output->writeln('<error>Failed to index entity with ID ' . $document->getEntityId() . '</error>');
188
				}
189
				if($entitiesIndexed % 50 === 0) {
190
					$entityManager->flush();
191
				}
192
			}
193
194
		}
195
		$entityManager->flush();
196
		$entityManager->clear();
197
		$progressBar->finish();
198
		$output->writeln('');
199
		$output->writeln('<comment>Indexed ' . $entitiesIndexed . ' entities</comment>');
200
	}
201
202
}