| Total Complexity | 58 |
| Total Lines | 429 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like AdminSearchRegistry often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AdminSearchRegistry, and based on these observations, apply Extract Interface, too.
| 1 | <?php declare(strict_types=1); |
||
| 26 | class AdminSearchRegistry implements MessageHandlerInterface, EventSubscriberInterface |
||
|
|
|||
| 27 | { |
||
| 28 | /** |
||
| 29 | * @var array<string, mixed> |
||
| 30 | */ |
||
| 31 | private array $indexer; |
||
| 32 | |||
| 33 | private Connection $connection; |
||
| 34 | |||
| 35 | private MessageBusInterface $queue; |
||
| 36 | |||
| 37 | private EventDispatcherInterface $dispatcher; |
||
| 38 | |||
| 39 | private Client $client; |
||
| 40 | |||
| 41 | private AdminElasticsearchHelper $adminEsHelper; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @var array<mixed> |
||
| 45 | */ |
||
| 46 | private array $config; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var array<mixed> |
||
| 50 | */ |
||
| 51 | private array $mapping; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @param AbstractAdminIndexer[] $indexer |
||
| 55 | * @param array<mixed> $config |
||
| 56 | * @param array<mixed> $mapping |
||
| 57 | */ |
||
| 58 | public function __construct( |
||
| 59 | $indexer, |
||
| 60 | Connection $connection, |
||
| 61 | MessageBusInterface $queue, |
||
| 62 | EventDispatcherInterface $dispatcher, |
||
| 63 | Client $client, |
||
| 64 | AdminElasticsearchHelper $adminEsHelper, |
||
| 65 | array $config, |
||
| 66 | array $mapping |
||
| 67 | ) { |
||
| 68 | $this->indexer = $indexer instanceof \Traversable ? iterator_to_array($indexer) : $indexer; |
||
| 69 | $this->connection = $connection; |
||
| 70 | $this->queue = $queue; |
||
| 71 | $this->dispatcher = $dispatcher; |
||
| 72 | $this->client = $client; |
||
| 73 | $this->adminEsHelper = $adminEsHelper; |
||
| 74 | $this->mapping = $mapping; |
||
| 75 | |||
| 76 | if (isset($config['settings']['index'])) { |
||
| 77 | if (\array_key_exists('number_of_shards', $config['settings']['index']) && $config['settings']['index']['number_of_shards'] === null) { |
||
| 78 | unset($config['settings']['index']['number_of_shards']); |
||
| 79 | } |
||
| 80 | |||
| 81 | if (\array_key_exists('number_of_replicas', $config['settings']['index']) && $config['settings']['index']['number_of_replicas'] === null) { |
||
| 82 | unset($config['settings']['index']['number_of_replicas']); |
||
| 83 | } |
||
| 84 | } |
||
| 85 | |||
| 86 | $this->config = $config; |
||
| 87 | } |
||
| 88 | |||
| 89 | public function __invoke(AdminSearchIndexingMessage $message): void |
||
| 90 | { |
||
| 91 | $indexer = $this->getIndexer($message->getEntity()); |
||
| 92 | |||
| 93 | $documents = $indexer->fetch($message->getIds()); |
||
| 94 | |||
| 95 | $this->push($indexer, $message->getIndices(), $documents, $message->getIds()); |
||
| 96 | } |
||
| 97 | |||
| 98 | public static function getSubscribedEvents(): array |
||
| 99 | { |
||
| 100 | return [ |
||
| 101 | EntityWrittenContainerEvent::class => [ |
||
| 102 | ['refresh', -1000], |
||
| 103 | ], |
||
| 104 | ]; |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * @return iterable<class-string> |
||
| 109 | */ |
||
| 110 | public static function getHandledMessages(): iterable |
||
| 111 | { |
||
| 112 | return [ |
||
| 113 | AdminSearchIndexingMessage::class, |
||
| 114 | ]; |
||
| 115 | } |
||
| 116 | |||
| 117 | public function iterate(AdminIndexingBehavior $indexingBehavior): void |
||
| 155 | } |
||
| 156 | |||
| 157 | public function refresh(EntityWrittenContainerEvent $event): void |
||
| 158 | { |
||
| 159 | if ($this->adminEsHelper->getEnabled() === false || !$this->isIndexedEntityWritten($event)) { |
||
| 160 | return; |
||
| 161 | } |
||
| 162 | |||
| 163 | if ($this->adminEsHelper->getRefreshIndices()) { |
||
| 164 | $this->refreshIndices(); |
||
| 165 | } |
||
| 166 | |||
| 167 | /** @var array<string, string> $indices */ |
||
| 168 | $indices = $this->connection->fetchAllKeyValue('SELECT `alias`, `index` FROM admin_elasticsearch_index_task'); |
||
| 169 | |||
| 170 | if (empty($indices)) { |
||
| 171 | return; |
||
| 172 | } |
||
| 173 | |||
| 174 | foreach ($this->indexer as $indexer) { |
||
| 175 | $ids = $event->getPrimaryKeys($indexer->getEntity()); |
||
| 176 | |||
| 177 | if (empty($ids)) { |
||
| 178 | continue; |
||
| 179 | } |
||
| 180 | $documents = $indexer->fetch($ids); |
||
| 181 | |||
| 182 | $this->push($indexer, $indices, $documents, $ids); |
||
| 183 | } |
||
| 184 | } |
||
| 185 | |||
| 186 | /** |
||
| 187 | * @return AbstractAdminIndexer[] |
||
| 188 | */ |
||
| 189 | public function getIndexers(): iterable |
||
| 190 | { |
||
| 191 | return $this->indexer; |
||
| 192 | } |
||
| 193 | |||
| 194 | public function getIndexer(string $name): AbstractAdminIndexer |
||
| 195 | { |
||
| 196 | $indexer = $this->indexer[$name] ?? null; |
||
| 197 | if ($indexer) { |
||
| 198 | return $indexer; |
||
| 199 | } |
||
| 200 | |||
| 201 | throw new ElasticsearchIndexingException([\sprintf('Indexer for name %s not found', $name)]); |
||
| 202 | } |
||
| 203 | |||
| 204 | private function isIndexedEntityWritten(EntityWrittenContainerEvent $event): bool |
||
| 205 | { |
||
| 206 | foreach ($this->indexer as $indexer) { |
||
| 207 | $ids = $event->getPrimaryKeys($indexer->getEntity()); |
||
| 208 | |||
| 209 | if (!empty($ids)) { |
||
| 210 | return true; |
||
| 211 | } |
||
| 212 | } |
||
| 213 | |||
| 214 | return false; |
||
| 215 | } |
||
| 216 | |||
| 217 | /** |
||
| 218 | * @param array<string, string> $indices |
||
| 219 | * @param array<string, array<string|int, string>> $data |
||
| 220 | * @param array<string> $ids |
||
| 221 | */ |
||
| 222 | private function push(AbstractAdminIndexer $indexer, array $indices, array $data, array $ids): void |
||
| 259 | } |
||
| 260 | } |
||
| 261 | |||
| 262 | /** |
||
| 263 | * @param array<string> $entities |
||
| 264 | * |
||
| 265 | * @throws \Doctrine\DBAL\Exception |
||
| 266 | * |
||
| 267 | * @return array<string, string> |
||
| 268 | */ |
||
| 269 | private function createIndices(array $entities): array |
||
| 270 | { |
||
| 271 | $indexTasks = []; |
||
| 272 | $indices = []; |
||
| 273 | foreach ($entities as $entityName) { |
||
| 274 | $indexer = $this->getIndexer($entityName); |
||
| 275 | $alias = $this->adminEsHelper->getIndex($indexer->getName()); |
||
| 276 | $index = $alias . '_' . time(); |
||
| 277 | |||
| 278 | if ($this->indexExists($index)) { |
||
| 279 | continue; |
||
| 280 | } |
||
| 281 | |||
| 282 | $indices[$alias] = $index; |
||
| 283 | |||
| 284 | $this->create($indexer, $index, $alias); |
||
| 285 | |||
| 286 | $iterator = $indexer->getIterator(); |
||
| 287 | $indexTasks[] = [ |
||
| 288 | 'id' => Uuid::randomBytes(), |
||
| 289 | '`entity`' => $indexer->getEntity(), |
||
| 290 | '`index`' => $index, |
||
| 291 | '`alias`' => $alias, |
||
| 292 | '`doc_count`' => $iterator->fetchCount(), |
||
| 293 | ]; |
||
| 294 | } |
||
| 295 | |||
| 296 | $this->connection->executeStatement( |
||
| 297 | 'DELETE FROM admin_elasticsearch_index_task WHERE `entity` IN (:entities)', |
||
| 298 | ['entities' => $entities], |
||
| 299 | ['entities' => Connection::PARAM_STR_ARRAY] |
||
| 300 | ); |
||
| 301 | |||
| 302 | foreach ($indexTasks as $task) { |
||
| 303 | $this->connection->insert('admin_elasticsearch_index_task', $task); |
||
| 304 | } |
||
| 305 | |||
| 306 | return $indices; |
||
| 307 | } |
||
| 308 | |||
| 309 | private function refreshIndices(): void |
||
| 343 | } |
||
| 344 | } |
||
| 345 | |||
| 346 | private function create(AbstractAdminIndexer $indexer, string $index, string $alias): void |
||
| 347 | { |
||
| 348 | $mapping = $indexer->mapping([ |
||
| 349 | 'properties' => [ |
||
| 350 | 'id' => ['type' => 'keyword'], |
||
| 351 | 'textBoosted' => ['type' => 'text'], |
||
| 352 | 'text' => ['type' => 'text'], |
||
| 353 | 'entityName' => ['type' => 'keyword'], |
||
| 354 | 'parameters' => ['type' => 'keyword'], |
||
| 355 | ], |
||
| 356 | ]); |
||
| 357 | |||
| 358 | $mapping = array_merge_recursive($mapping, $this->mapping); |
||
| 359 | |||
| 360 | $body = array_merge( |
||
| 361 | $this->config, |
||
| 362 | ['mappings' => $mapping] |
||
| 363 | ); |
||
| 364 | |||
| 365 | $this->client->indices()->create([ |
||
| 366 | 'index' => $index, |
||
| 367 | 'body' => $body, |
||
| 368 | ]); |
||
| 369 | |||
| 370 | $this->createAliasIfNotExisting($index, $alias); |
||
| 371 | } |
||
| 372 | |||
| 373 | private function indexExists(string $name): bool |
||
| 374 | { |
||
| 375 | return $this->client->indices()->exists(['index' => $name]); |
||
| 376 | } |
||
| 377 | |||
| 378 | private function aliasExists(string $alias): bool |
||
| 379 | { |
||
| 380 | return $this->client->indices()->existsAlias(['name' => $alias]); |
||
| 381 | } |
||
| 382 | |||
| 383 | /** |
||
| 384 | * @param array<string, array<array<string, mixed>>> $result |
||
| 385 | * |
||
| 386 | * @return array<array{reason: string}|string> |
||
| 387 | */ |
||
| 388 | private function parseErrors(array $result): array |
||
| 389 | { |
||
| 390 | $errors = []; |
||
| 391 | foreach ($result['items'] as $item) { |
||
| 392 | $item = $item['index'] ?? $item['delete']; |
||
| 393 | |||
| 394 | if (\in_array($item['status'], [200, 201], true)) { |
||
| 395 | continue; |
||
| 396 | } |
||
| 397 | |||
| 398 | $errors[] = [ |
||
| 399 | 'index' => $item['_index'], |
||
| 400 | 'id' => $item['_id'], |
||
| 401 | 'type' => $item['error']['type'] ?? $item['_type'], |
||
| 402 | 'reason' => $item['error']['reason'] ?? $item['result'], |
||
| 403 | ]; |
||
| 404 | } |
||
| 405 | |||
| 406 | return $errors; |
||
| 407 | } |
||
| 408 | |||
| 409 | private function createAliasIfNotExisting(string $index, string $alias): void |
||
| 410 | { |
||
| 411 | $exist = $this->client->indices()->existsAlias(['name' => $alias]); |
||
| 412 | |||
| 413 | if ($exist) { |
||
| 414 | return; |
||
| 415 | } |
||
| 416 | |||
| 417 | $this->putAlias($index, $alias); |
||
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * @param array<string, string> $indices |
||
| 422 | */ |
||
| 423 | private function swapAlias($indices): void |
||
| 445 | } |
||
| 446 | } |
||
| 447 | } |
||
| 448 | |||
| 449 | private function putAlias(string $index, string $alias): void |
||
| 455 | } |
||
| 456 | } |
||
| 457 |
This interface has been deprecated. The supplier of the interface has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.